mirror of
https://github.com/enso-org/enso.git
synced 2024-11-21 16:36:59 +03:00
Update java formatter sbt plugin (#8543)
Add a local clone of javaFormatter plugin. The upstream is not maintained anymore. And we need to update it to use the newest Google java formatter because the old one, that we use, cannot format sources with Java 8+ syntax. # Important Notes Update to Google java formatter 1.18.1 - https://github.com/google/google-java-format/releases/tag/v1.18.1
This commit is contained in:
parent
56cc9561b1
commit
c1098865f2
4
.github/workflows/formatting.yml
vendored
4
.github/workflows/formatting.yml
vendored
@ -8,9 +8,9 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
# Please ensure that this is in sync with graalVersion in build.sbt
|
# Please ensure that this is in sync with graalVersion in build.sbt
|
||||||
javaVersion: 17.0.7
|
javaVersion: 21.0.1
|
||||||
# Please ensure that this is in sync with project/build.properties
|
# Please ensure that this is in sync with project/build.properties
|
||||||
sbtVersion: 1.9.0
|
sbtVersion: 1.9.7
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test_formatting:
|
test_formatting:
|
||||||
|
6
.jvmopts
6
.jvmopts
@ -1,3 +1,9 @@
|
|||||||
-Xss16M
|
-Xss16M
|
||||||
-Xmx4G
|
-Xmx4G
|
||||||
-XX:+UseCompressedOops
|
-XX:+UseCompressedOops
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
|
||||||
|
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
package org.enso.interpreter.dsl.test;
|
package org.enso.interpreter.dsl.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.nodes.DirectCallNode;
|
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.enso.interpreter.node.InlineableNode;
|
import org.enso.interpreter.node.InlineableNode;
|
||||||
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class InliningBuiltinsTest {
|
public class InliningBuiltinsTest {
|
||||||
|
|
||||||
/** @see InliningBuiltinsInNode#execute(long, long) */
|
/**
|
||||||
|
* @see InliningBuiltinsInNode#execute(long, long)
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWithoutVirtualFrame() {
|
public void executeWithoutVirtualFrame() {
|
||||||
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
var fn = InliningBuiltinsInMethodGen.makeFunction(null);
|
||||||
@ -19,18 +22,27 @@ public class InliningBuiltinsTest {
|
|||||||
var call = root.createInlineableNode();
|
var call = root.createInlineableNode();
|
||||||
var clazz = call.getClass();
|
var clazz = call.getClass();
|
||||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||||
assertEquals("org.enso.interpreter.node.InlineableNode$Root", clazz.getEnclosingClass().getInterfaces()[0].getName());
|
assertEquals(
|
||||||
|
"org.enso.interpreter.node.InlineableNode$Root",
|
||||||
|
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||||
|
|
||||||
var res = WithFrame.invoke((frame) -> {
|
var res =
|
||||||
return call.call(frame, Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 5L, 7L }));
|
WithFrame.invoke(
|
||||||
});
|
(frame) -> {
|
||||||
|
return call.call(
|
||||||
|
frame,
|
||||||
|
Function.ArgumentsHelper.buildArguments(
|
||||||
|
null, null, new Object[] {null, 5L, 7L}));
|
||||||
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
} else {
|
} else {
|
||||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see InliningBuiltinsOutNode#execute(com.oracle.truffle.api.frame.VirtualFrame, long, long) */
|
/**
|
||||||
|
* @see InliningBuiltinsOutNode#execute(com.oracle.truffle.api.frame.VirtualFrame, long, long)
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWithVirtualFrame() {
|
public void executeWithVirtualFrame() {
|
||||||
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
var fn = InliningBuiltinsOutMethodGen.makeFunction(null);
|
||||||
@ -41,14 +53,20 @@ public class InliningBuiltinsTest {
|
|||||||
var clazz = call.getClass().getSuperclass();
|
var clazz = call.getClass().getSuperclass();
|
||||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||||
|
|
||||||
var res = WithFrame.invoke((frame) -> {
|
var res =
|
||||||
return call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 3L, 9L }));
|
WithFrame.invoke(
|
||||||
});
|
(frame) -> {
|
||||||
|
return call.call(
|
||||||
|
Function.ArgumentsHelper.buildArguments(
|
||||||
|
null, null, new Object[] {null, 3L, 9L}));
|
||||||
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see InliningBuiltinsNeedsNode#execute(long, long) */
|
/**
|
||||||
|
* @see InliningBuiltinsNeedsNode#execute(long, long)
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWhenNeedsVirtualFrame() {
|
public void executeWhenNeedsVirtualFrame() {
|
||||||
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
var fn = InliningBuiltinsNeedsMethodGen.makeFunction(null);
|
||||||
@ -59,14 +77,20 @@ public class InliningBuiltinsTest {
|
|||||||
var clazz = call.getClass().getSuperclass();
|
var clazz = call.getClass().getSuperclass();
|
||||||
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
assertEquals("com.oracle.truffle.api.nodes.DirectCallNode", clazz.getName());
|
||||||
|
|
||||||
var res = WithFrame.invoke((frame) -> {
|
var res =
|
||||||
return call.call(Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 3L, 9L }));
|
WithFrame.invoke(
|
||||||
});
|
(frame) -> {
|
||||||
|
return call.call(
|
||||||
|
Function.ArgumentsHelper.buildArguments(
|
||||||
|
null, null, new Object[] {null, 3L, 9L}));
|
||||||
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see InliningBuiltinsNeedNotNode#execute(com.oracle.truffle.api.frame.VirtualFrame, long, long) */
|
/**
|
||||||
|
* @see InliningBuiltinsNeedNotNode#execute(com.oracle.truffle.api.frame.VirtualFrame, long, long)
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void executeWhenNeedNotVirtualFrame() {
|
public void executeWhenNeedNotVirtualFrame() {
|
||||||
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
var fn = InliningBuiltinsNeedNotMethodGen.makeFunction(null);
|
||||||
@ -74,11 +98,18 @@ public class InliningBuiltinsTest {
|
|||||||
var call = root.createInlineableNode();
|
var call = root.createInlineableNode();
|
||||||
var clazz = call.getClass();
|
var clazz = call.getClass();
|
||||||
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
assertEquals("InlineableNode", clazz.getSuperclass().getSimpleName());
|
||||||
assertEquals("org.enso.interpreter.node.InlineableNode$Root", clazz.getEnclosingClass().getInterfaces()[0].getName());
|
assertEquals(
|
||||||
|
"org.enso.interpreter.node.InlineableNode$Root",
|
||||||
|
clazz.getEnclosingClass().getInterfaces()[0].getName());
|
||||||
|
|
||||||
var res = WithFrame.invoke((frame) -> {
|
var res =
|
||||||
return call.call(frame, Function.ArgumentsHelper.buildArguments(null, null, new Object[] { null, 5L, 7L }));
|
WithFrame.invoke(
|
||||||
});
|
(frame) -> {
|
||||||
|
return call.call(
|
||||||
|
frame,
|
||||||
|
Function.ArgumentsHelper.buildArguments(
|
||||||
|
null, null, new Object[] {null, 5L, 7L}));
|
||||||
|
});
|
||||||
assertEquals(12L, res);
|
assertEquals(12L, res);
|
||||||
} else {
|
} else {
|
||||||
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
fail("It is inlineable: " + fn.getCallTarget().getRootNode());
|
||||||
|
@ -10,13 +10,12 @@ public class ThrowBuiltinNode extends Node {
|
|||||||
public Object execute(Text type, long exceptionIdx) {
|
public Object execute(Text type, long exceptionIdx) {
|
||||||
switch (type.toString()) {
|
switch (type.toString()) {
|
||||||
case "exception" -> {
|
case "exception" -> {
|
||||||
Supplier<RuntimeException> exceptionSupplier =
|
Supplier<RuntimeException> exceptionSupplier =
|
||||||
ThrowableCatchTest.exceptionSuppliers.get((int) exceptionIdx);
|
ThrowableCatchTest.exceptionSuppliers.get((int) exceptionIdx);
|
||||||
throw exceptionSupplier.get();
|
throw exceptionSupplier.get();
|
||||||
}
|
}
|
||||||
case "error" -> {
|
case "error" -> {
|
||||||
Supplier<Error> errorSupplier =
|
Supplier<Error> errorSupplier = ThrowableCatchTest.errorSuppliers.get((int) exceptionIdx);
|
||||||
ThrowableCatchTest.errorSuppliers.get((int) exceptionIdx);
|
|
||||||
throw errorSupplier.get();
|
throw errorSupplier.get();
|
||||||
}
|
}
|
||||||
default -> throw new AssertionError("Unknown type: " + type);
|
default -> throw new AssertionError("Unknown type: " + type);
|
||||||
|
@ -4,12 +4,11 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
|
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
|
||||||
import java.io.ByteArrayOutputStream;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
@ -24,7 +23,6 @@ import org.graalvm.polyglot.io.IOAccess;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Most of the exceptions thrown by the builtin methods, generated by {@link
|
* Most of the exceptions thrown by the builtin methods, generated by {@link
|
||||||
@ -72,10 +70,7 @@ public class ThrowableCatchTest {
|
|||||||
.allowAllAccess(true)
|
.allowAllAccess(true)
|
||||||
.logHandler(System.err)
|
.logHandler(System.err)
|
||||||
.option(RuntimeOptions.STRICT_ERRORS, "true")
|
.option(RuntimeOptions.STRICT_ERRORS, "true")
|
||||||
.option(
|
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||||
RuntimeOptions.LOG_LEVEL,
|
|
||||||
Level.WARNING.getName()
|
|
||||||
)
|
|
||||||
.option(
|
.option(
|
||||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||||
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||||
|
@ -5,7 +5,9 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
/** A component that should be initialized. */
|
/** A component that should be initialized. */
|
||||||
public interface InitializationComponent {
|
public interface InitializationComponent {
|
||||||
|
|
||||||
/** @return `true` if the component is initialized */
|
/**
|
||||||
|
* @return `true` if the component is initialized
|
||||||
|
*/
|
||||||
boolean isInitialized();
|
boolean isInitialized();
|
||||||
|
|
||||||
/** Initialize the component. */
|
/** Initialize the component. */
|
||||||
|
@ -163,7 +163,8 @@ public class RepoInitialization implements InitializationComponent {
|
|||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
} else if (error instanceof FileSystemException) {
|
} else if (error instanceof FileSystemException) {
|
||||||
logger.error(
|
logger.error(
|
||||||
"Failed to delete the database file. Attempt #{}. The file will be removed during the shutdown.",
|
"Failed to delete the database file. Attempt #{}. The file will be removed during the"
|
||||||
|
+ " shutdown.",
|
||||||
retries + 1,
|
retries + 1,
|
||||||
error);
|
error);
|
||||||
Runtime.getRuntime()
|
Runtime.getRuntime()
|
||||||
|
@ -8,7 +8,6 @@ import java.util.UUID;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
import java.util.logging.XMLFormatter;
|
import java.util.logging.XMLFormatter;
|
||||||
|
|
||||||
import org.enso.languageserver.runtime.RuntimeConnector;
|
import org.enso.languageserver.runtime.RuntimeConnector;
|
||||||
import org.enso.polyglot.runtime.Runtime;
|
import org.enso.polyglot.runtime.Runtime;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$Request;
|
import org.enso.polyglot.runtime.Runtime$Api$Request;
|
||||||
@ -55,9 +54,7 @@ public final class RuntimeEventsMonitor implements EventsMonitor {
|
|||||||
this(out, Clock.systemUTC());
|
this(out, Clock.systemUTC());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Direction of the message. */
|
||||||
* Direction of the message.
|
|
||||||
*/
|
|
||||||
private enum Direction {
|
private enum Direction {
|
||||||
REQUEST,
|
REQUEST,
|
||||||
RESPONSE
|
RESPONSE
|
||||||
|
@ -11,13 +11,19 @@ public interface IdExecutionService {
|
|||||||
|
|
||||||
public abstract class Info {
|
public abstract class Info {
|
||||||
|
|
||||||
/** @return UUID of the node, never {@code null}. */
|
/**
|
||||||
|
* @return UUID of the node, never {@code null}.
|
||||||
|
*/
|
||||||
public abstract UUID getId();
|
public abstract UUID getId();
|
||||||
|
|
||||||
/** @return associated result or {@code null} if there is no associated result. */
|
/**
|
||||||
|
* @return associated result or {@code null} if there is no associated result.
|
||||||
|
*/
|
||||||
public abstract Object getResult();
|
public abstract Object getResult();
|
||||||
|
|
||||||
/** @return {@code true} when the result is panic, {@code false} otherwise. */
|
/**
|
||||||
|
* @return {@code true} when the result is panic, {@code false} otherwise.
|
||||||
|
*/
|
||||||
public abstract boolean isPanic();
|
public abstract boolean isPanic();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,5 +3,4 @@ package org.enso.compiler.context;
|
|||||||
/**
|
/**
|
||||||
* A representation of a pointer into a stack frame at a given number of levels above the current.
|
* A representation of a pointer into a stack frame at a given number of levels above the current.
|
||||||
*/
|
*/
|
||||||
public record FramePointer(int parentLevel, int frameSlotIdx) {
|
public record FramePointer(int parentLevel, int frameSlotIdx) {}
|
||||||
}
|
|
||||||
|
@ -10,9 +10,4 @@ import org.enso.text.editing.model.TextEdit;
|
|||||||
* @param edit the editor change
|
* @param edit the editor change
|
||||||
* @param newIr the new literal
|
* @param newIr the new literal
|
||||||
*/
|
*/
|
||||||
public record SimpleUpdate(
|
public record SimpleUpdate(Literal ir, TextEdit edit, Literal newIr) {}
|
||||||
Literal ir,
|
|
||||||
TextEdit edit,
|
|
||||||
Literal newIr
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
@ -38,10 +38,7 @@ public final class ExportSymbolAnalysis implements IRPass {
|
|||||||
@Override
|
@Override
|
||||||
public Seq<IRPass> precursorPasses() {
|
public Seq<IRPass> precursorPasses() {
|
||||||
if (precursorPasses == null) {
|
if (precursorPasses == null) {
|
||||||
List<IRPass> passes = List.of(
|
List<IRPass> passes = List.of(BindingAnalysis$.MODULE$, ImportSymbolAnalysis$.MODULE$);
|
||||||
BindingAnalysis$.MODULE$,
|
|
||||||
ImportSymbolAnalysis$.MODULE$
|
|
||||||
);
|
|
||||||
precursorPasses = CollectionConverters.asScala(passes).toList();
|
precursorPasses = CollectionConverters.asScala(passes).toList();
|
||||||
}
|
}
|
||||||
return precursorPasses;
|
return precursorPasses;
|
||||||
@ -59,46 +56,52 @@ public final class ExportSymbolAnalysis implements IRPass {
|
|||||||
List<Export> exportErrors = new ArrayList<>();
|
List<Export> exportErrors = new ArrayList<>();
|
||||||
var bindingsMap = (BindingsMap) moduleIr.passData().get(BindingAnalysis$.MODULE$).get();
|
var bindingsMap = (BindingsMap) moduleIr.passData().get(BindingAnalysis$.MODULE$).get();
|
||||||
|
|
||||||
moduleIr.exports().foreach(export -> switch (export) {
|
moduleIr
|
||||||
case Export.Module exportMod -> {
|
.exports()
|
||||||
var exportNameParts = exportMod.name().parts();
|
.foreach(
|
||||||
var symbolName = exportMod.name().parts().last();
|
export ->
|
||||||
assert exportNameParts.size() > 1;
|
switch (export) {
|
||||||
var moduleOrTypeName = exportNameParts.apply(exportNameParts.size() - 2);
|
case Export.Module exportMod -> {
|
||||||
var foundResolvedExp = findResolvedExportForIr(export, bindingsMap);
|
var exportNameParts = exportMod.name().parts();
|
||||||
if (foundResolvedExp == null) {
|
var symbolName = exportMod.name().parts().last();
|
||||||
exportErrors.add(
|
assert exportNameParts.size() > 1;
|
||||||
ImportExport.apply(
|
var moduleOrTypeName = exportNameParts.apply(exportNameParts.size() - 2);
|
||||||
symbolName,
|
var foundResolvedExp = findResolvedExportForIr(export, bindingsMap);
|
||||||
new ImportExport.SymbolDoesNotExist(symbolName.name(), moduleOrTypeName.name()),
|
if (foundResolvedExp == null) {
|
||||||
ImportExport.apply$default$3(),
|
exportErrors.add(
|
||||||
ImportExport.apply$default$4()
|
ImportExport.apply(
|
||||||
)
|
symbolName,
|
||||||
);
|
new ImportExport.SymbolDoesNotExist(
|
||||||
} else {
|
symbolName.name(), moduleOrTypeName.name()),
|
||||||
if (exportMod.onlyNames().isDefined()) {
|
ImportExport.apply$default$3(),
|
||||||
assert exportMod.onlyNames().isDefined();
|
ImportExport.apply$default$4()));
|
||||||
var exportedSymbols = exportMod.onlyNames().get();
|
} else {
|
||||||
exportedSymbols.foreach(exportedSymbol -> {
|
if (exportMod.onlyNames().isDefined()) {
|
||||||
var foundSymbols = foundResolvedExp.target().findExportedSymbolsFor(exportedSymbol.name());
|
assert exportMod.onlyNames().isDefined();
|
||||||
if (foundSymbols.isEmpty()) {
|
var exportedSymbols = exportMod.onlyNames().get();
|
||||||
exportErrors.add(
|
exportedSymbols.foreach(
|
||||||
ImportExport.apply(
|
exportedSymbol -> {
|
||||||
exportedSymbol,
|
var foundSymbols =
|
||||||
new ImportExport.SymbolDoesNotExist(exportedSymbol.name(), moduleOrTypeName.name()),
|
foundResolvedExp
|
||||||
ImportExport.apply$default$3(),
|
.target()
|
||||||
ImportExport.apply$default$4()
|
.findExportedSymbolsFor(exportedSymbol.name());
|
||||||
)
|
if (foundSymbols.isEmpty()) {
|
||||||
);
|
exportErrors.add(
|
||||||
}
|
ImportExport.apply(
|
||||||
return null;
|
exportedSymbol,
|
||||||
});
|
new ImportExport.SymbolDoesNotExist(
|
||||||
}
|
exportedSymbol.name(), moduleOrTypeName.name()),
|
||||||
}
|
ImportExport.apply$default$3(),
|
||||||
yield null;
|
ImportExport.apply$default$4()));
|
||||||
}
|
}
|
||||||
default -> export;
|
return null;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield null;
|
||||||
|
}
|
||||||
|
default -> export;
|
||||||
|
});
|
||||||
|
|
||||||
if (exportErrors.isEmpty()) {
|
if (exportErrors.isEmpty()) {
|
||||||
return moduleIr;
|
return moduleIr;
|
||||||
@ -110,8 +113,7 @@ public final class ExportSymbolAnalysis implements IRPass {
|
|||||||
moduleIr.location(),
|
moduleIr.location(),
|
||||||
moduleIr.passData(),
|
moduleIr.passData(),
|
||||||
moduleIr.diagnostics(),
|
moduleIr.diagnostics(),
|
||||||
moduleIr.id()
|
moduleIr.id());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,18 +124,24 @@ public final class ExportSymbolAnalysis implements IRPass {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a resolved export that corresponds to the export IR.
|
* Finds a resolved export that corresponds to the export IR.
|
||||||
|
*
|
||||||
* @param exportIr Export IR that is being resolved
|
* @param exportIr Export IR that is being resolved
|
||||||
* @param bindingsMap Bindings map of the module that contains the export IR
|
* @param bindingsMap Bindings map of the module that contains the export IR
|
||||||
* @return null if no resolved export was found, otherwise the resolved export
|
* @return null if no resolved export was found, otherwise the resolved export
|
||||||
*/
|
*/
|
||||||
private BindingsMap.ExportedModule findResolvedExportForIr(Export exportIr, BindingsMap bindingsMap) {
|
private BindingsMap.ExportedModule findResolvedExportForIr(
|
||||||
|
Export exportIr, BindingsMap bindingsMap) {
|
||||||
switch (exportIr) {
|
switch (exportIr) {
|
||||||
case Export.Module exportedModIr -> {
|
case Export.Module exportedModIr -> {
|
||||||
var exportedModName = exportedModIr.name().name();
|
var exportedModName = exportedModIr.name().name();
|
||||||
var foundResolvedExp = bindingsMap.resolvedExports().find(resolvedExport -> {
|
var foundResolvedExp =
|
||||||
var resolvedExportName = resolvedExport.target().qualifiedName();
|
bindingsMap
|
||||||
return resolvedExportName.toString().equals(exportedModName);
|
.resolvedExports()
|
||||||
});
|
.find(
|
||||||
|
resolvedExport -> {
|
||||||
|
var resolvedExportName = resolvedExport.target().qualifiedName();
|
||||||
|
return resolvedExportName.toString().equals(exportedModName);
|
||||||
|
});
|
||||||
return foundResolvedExp.isEmpty() ? null : foundResolvedExp.get();
|
return foundResolvedExp.isEmpty() ? null : foundResolvedExp.get();
|
||||||
}
|
}
|
||||||
default -> throw new IllegalStateException("Unexpected value: " + exportIr);
|
default -> throw new IllegalStateException("Unexpected value: " + exportIr);
|
||||||
|
@ -20,11 +20,13 @@ import scala.jdk.javaapi.CollectionConverters;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates through all the imports and exports of non-synthetic modules and ensures that:
|
* Iterates through all the imports and exports of non-synthetic modules and ensures that:
|
||||||
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>No private module is exported</li>
|
* <li>No private module is exported
|
||||||
* <li>No private module from a different project is imported</li>
|
* <li>No private module from a different project is imported
|
||||||
* <li>Hierarchy of modules and submodules does not mix private and public modules</li>
|
* <li>Hierarchy of modules and submodules does not mix private and public modules
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
* Inserts errors into imports/exports IRs if the above conditions are violated.
|
* Inserts errors into imports/exports IRs if the above conditions are violated.
|
||||||
*/
|
*/
|
||||||
public final class PrivateModuleAnalysis implements IRPass {
|
public final class PrivateModuleAnalysis implements IRPass {
|
||||||
@ -45,10 +47,7 @@ public final class PrivateModuleAnalysis implements IRPass {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Seq<IRPass> precursorPasses() {
|
public Seq<IRPass> precursorPasses() {
|
||||||
List<IRPass> passes = List.of(
|
List<IRPass> passes = List.of(BindingAnalysis$.MODULE$, ImportSymbolAnalysis$.MODULE$);
|
||||||
BindingAnalysis$.MODULE$,
|
|
||||||
ImportSymbolAnalysis$.MODULE$
|
|
||||||
);
|
|
||||||
return CollectionConverters.asScala(passes).toList();
|
return CollectionConverters.asScala(passes).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,78 +67,80 @@ public final class PrivateModuleAnalysis implements IRPass {
|
|||||||
var isCurrentModulePrivate = moduleIr.isPrivate();
|
var isCurrentModulePrivate = moduleIr.isPrivate();
|
||||||
|
|
||||||
// Ensure that imported modules from a different project are not private.
|
// Ensure that imported modules from a different project are not private.
|
||||||
bindingsMap.resolvedImports().foreach(resolvedImp -> {
|
bindingsMap
|
||||||
var importedModule = resolvedImp.target().module().unsafeAsModule("should succeed");
|
.resolvedImports()
|
||||||
var importedModuleName = importedModule.getName().toString();
|
.foreach(
|
||||||
var importedModulePackage = importedModule.getPackage();
|
resolvedImp -> {
|
||||||
if (currentPackage != null
|
var importedModule = resolvedImp.target().module().unsafeAsModule("should succeed");
|
||||||
&& !currentPackage.equals(importedModulePackage)
|
var importedModuleName = importedModule.getName().toString();
|
||||||
&& importedModule.isPrivate()) {
|
var importedModulePackage = importedModule.getPackage();
|
||||||
importErrors.add(ImportExport.apply(
|
if (currentPackage != null
|
||||||
resolvedImp.importDef(),
|
&& !currentPackage.equals(importedModulePackage)
|
||||||
new ImportExport.ImportPrivateModule(importedModuleName),
|
&& importedModule.isPrivate()) {
|
||||||
ImportExport.apply$default$3(),
|
importErrors.add(
|
||||||
ImportExport.apply$default$4()
|
ImportExport.apply(
|
||||||
));
|
resolvedImp.importDef(),
|
||||||
}
|
new ImportExport.ImportPrivateModule(importedModuleName),
|
||||||
return null;
|
ImportExport.apply$default$3(),
|
||||||
});
|
ImportExport.apply$default$4()));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
// Ensure that no symbols are exported from a private module.
|
// Ensure that no symbols are exported from a private module.
|
||||||
if (isCurrentModulePrivate && containsExport(moduleIr)) {
|
if (isCurrentModulePrivate && containsExport(moduleIr)) {
|
||||||
exportErrors.add(ImportExport.apply(
|
exportErrors.add(
|
||||||
moduleIr.exports().apply(0),
|
ImportExport.apply(
|
||||||
new ImportExport.ExportSymbolsFromPrivateModule(moduleContext.getName().toString()),
|
moduleIr.exports().apply(0),
|
||||||
ImportExport.apply$default$3(),
|
new ImportExport.ExportSymbolsFromPrivateModule(moduleContext.getName().toString()),
|
||||||
ImportExport.apply$default$4()
|
ImportExport.apply$default$3(),
|
||||||
));
|
ImportExport.apply$default$4()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Ensure that private modules are not exported and that the hierarchy of submodules
|
// Ensure that private modules are not exported and that the hierarchy of submodules
|
||||||
// does not mix public and private modules.
|
// does not mix public and private modules.
|
||||||
bindingsMap
|
bindingsMap
|
||||||
.getDirectlyExportedModules()
|
.getDirectlyExportedModules()
|
||||||
.foreach(expModule -> {
|
.foreach(
|
||||||
var expModuleRef = expModule.target().module().unsafeAsModule("should succeed");
|
expModule -> {
|
||||||
if (expModuleRef.isPrivate()) {
|
var expModuleRef = expModule.target().module().unsafeAsModule("should succeed");
|
||||||
var associatedExportIR = findExportIRByName(moduleIr, expModuleRef.getName());
|
if (expModuleRef.isPrivate()) {
|
||||||
assert associatedExportIR.isDefined();
|
var associatedExportIR = findExportIRByName(moduleIr, expModuleRef.getName());
|
||||||
if (isSubmoduleName(moduleContext.getName(), expModuleRef.getName())) {
|
assert associatedExportIR.isDefined();
|
||||||
var haveSameVisibility = isCurrentModulePrivate == expModuleRef.isPrivate();
|
if (isSubmoduleName(moduleContext.getName(), expModuleRef.getName())) {
|
||||||
if (!haveSameVisibility) {
|
var haveSameVisibility = isCurrentModulePrivate == expModuleRef.isPrivate();
|
||||||
exportErrors.add(
|
if (!haveSameVisibility) {
|
||||||
ImportExport.apply(
|
exportErrors.add(
|
||||||
associatedExportIR.get(),
|
ImportExport.apply(
|
||||||
new ImportExport.SubmoduleVisibilityMismatch(
|
associatedExportIR.get(),
|
||||||
moduleContext.getName().toString(),
|
new ImportExport.SubmoduleVisibilityMismatch(
|
||||||
expModuleRef.getName().toString(),
|
moduleContext.getName().toString(),
|
||||||
isCurrentModulePrivate ? "private" : "public",
|
expModuleRef.getName().toString(),
|
||||||
expModuleRef.isPrivate() ? "private" : "public"
|
isCurrentModulePrivate ? "private" : "public",
|
||||||
),
|
expModuleRef.isPrivate() ? "private" : "public"),
|
||||||
ImportExport.apply$default$3(),
|
ImportExport.apply$default$3(),
|
||||||
ImportExport.apply$default$4()
|
ImportExport.apply$default$4()));
|
||||||
)
|
}
|
||||||
);
|
} else {
|
||||||
|
exportErrors.add(
|
||||||
|
ImportExport.apply(
|
||||||
|
associatedExportIR.get(),
|
||||||
|
new ImportExport.ExportPrivateModule(expModuleRef.getName().toString()),
|
||||||
|
ImportExport.apply$default$3(),
|
||||||
|
ImportExport.apply$default$4()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
return null;
|
||||||
exportErrors.add(
|
});
|
||||||
ImportExport.apply(
|
|
||||||
associatedExportIR.get(),
|
|
||||||
new ImportExport.ExportPrivateModule(expModuleRef.getName().toString()),
|
|
||||||
ImportExport.apply$default$3(),
|
|
||||||
ImportExport.apply$default$4()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
scala.collection.immutable.List<Import> convertedImports =
|
scala.collection.immutable.List<Import> convertedImports =
|
||||||
importErrors.isEmpty() ? moduleIr.imports() : CollectionConverters.asScala(importErrors).toList();
|
importErrors.isEmpty()
|
||||||
|
? moduleIr.imports()
|
||||||
|
: CollectionConverters.asScala(importErrors).toList();
|
||||||
scala.collection.immutable.List<Export> convertedExports =
|
scala.collection.immutable.List<Export> convertedExports =
|
||||||
exportErrors.isEmpty() ? moduleIr.exports() : CollectionConverters.asScala(exportErrors).toList();
|
exportErrors.isEmpty()
|
||||||
|
? moduleIr.exports()
|
||||||
|
: CollectionConverters.asScala(exportErrors).toList();
|
||||||
|
|
||||||
return moduleIr.copy(
|
return moduleIr.copy(
|
||||||
convertedImports,
|
convertedImports,
|
||||||
@ -148,15 +149,12 @@ public final class PrivateModuleAnalysis implements IRPass {
|
|||||||
moduleIr.location(),
|
moduleIr.location(),
|
||||||
moduleIr.passData(),
|
moduleIr.passData(),
|
||||||
moduleIr.diagnostics(),
|
moduleIr.diagnostics(),
|
||||||
moduleIr.id()
|
moduleIr.id());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSubmoduleName(QualifiedName parentModName, QualifiedName subModName) {
|
private boolean isSubmoduleName(QualifiedName parentModName, QualifiedName subModName) {
|
||||||
if (subModName.getParent().isDefined()) {
|
if (subModName.getParent().isDefined()) {
|
||||||
return parentModName.item().equals(
|
return parentModName.item().equals(subModName.getParent().get().item());
|
||||||
subModName.getParent().get().item()
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -167,30 +165,35 @@ public final class PrivateModuleAnalysis implements IRPass {
|
|||||||
return ir;
|
return ir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns true iff the given Module's IR contains an export that is not synthetic. */
|
||||||
* Returns true iff the given Module's IR contains an export that is not synthetic.
|
|
||||||
*/
|
|
||||||
private static boolean containsExport(Module moduleIr) {
|
private static boolean containsExport(Module moduleIr) {
|
||||||
return !moduleIr.exports().isEmpty() && moduleIr.exports().exists(exp -> {
|
return !moduleIr.exports().isEmpty()
|
||||||
if (exp instanceof Export.Module moduleExport) {
|
&& moduleIr
|
||||||
return !moduleExport.isSynthetic();
|
.exports()
|
||||||
} else {
|
.exists(
|
||||||
return false;
|
exp -> {
|
||||||
}
|
if (exp instanceof Export.Module moduleExport) {
|
||||||
});
|
return !moduleExport.isSynthetic();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Option<Export> findExportIRByName(Module moduleIr, QualifiedName fqn) {
|
private static Option<Export> findExportIRByName(Module moduleIr, QualifiedName fqn) {
|
||||||
return moduleIr.exports().find(exp -> {
|
return moduleIr
|
||||||
if (exp instanceof Export.Module expMod) {
|
.exports()
|
||||||
if (expMod.name().parts().last().name().equals(fqn.item())) {
|
.find(
|
||||||
return true;
|
exp -> {
|
||||||
}
|
if (exp instanceof Export.Module expMod) {
|
||||||
} else {
|
if (expMod.name().parts().last().name().equals(fqn.item())) {
|
||||||
throw new IllegalStateException("unknown exp: " + exp);
|
return true;
|
||||||
}
|
}
|
||||||
return null;
|
} else {
|
||||||
});
|
throw new IllegalStateException("unknown exp: " + exp);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,7 +22,9 @@ public final class MethodCallsCache {
|
|||||||
callsExecuted.add(call);
|
callsExecuted.add(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the set of executed calls. */
|
/**
|
||||||
|
* @return the set of executed calls.
|
||||||
|
*/
|
||||||
public Set<UUID> getCallsExecuted() {
|
public Set<UUID> getCallsExecuted() {
|
||||||
return callsExecuted;
|
return callsExecuted;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,9 @@ public final class RuntimeCache {
|
|||||||
return ref == null ? null : ref.get();
|
return ref == null ? null : ref.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return all cache keys. */
|
/**
|
||||||
|
* @return all cache keys.
|
||||||
|
*/
|
||||||
public Set<UUID> getKeys() {
|
public Set<UUID> getKeys() {
|
||||||
return cache.keySet();
|
return cache.keySet();
|
||||||
}
|
}
|
||||||
@ -65,7 +67,9 @@ public final class RuntimeCache {
|
|||||||
return types.put(key, typeName);
|
return types.put(key, typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the cached type of the expression */
|
/**
|
||||||
|
* @return the cached type of the expression
|
||||||
|
*/
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public String getType(UUID key) {
|
public String getType(UUID key) {
|
||||||
return types.get(key);
|
return types.get(key);
|
||||||
@ -87,13 +91,17 @@ public final class RuntimeCache {
|
|||||||
return calls.put(key, call);
|
return calls.put(key, call);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the cached function call associated with the expression. */
|
/**
|
||||||
|
* @return the cached function call associated with the expression.
|
||||||
|
*/
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public ExecutionService.FunctionCallInfo getCall(UUID key) {
|
public ExecutionService.FunctionCallInfo getCall(UUID key) {
|
||||||
return calls.get(key);
|
return calls.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the cached method calls. */
|
/**
|
||||||
|
* @return the cached method calls.
|
||||||
|
*/
|
||||||
public Set<UUID> getCalls() {
|
public Set<UUID> getCalls() {
|
||||||
return calls.keySet();
|
return calls.keySet();
|
||||||
}
|
}
|
||||||
@ -122,7 +130,9 @@ public final class RuntimeCache {
|
|||||||
types.clear();
|
types.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the weights of this cache. */
|
/**
|
||||||
|
* @return the weights of this cache.
|
||||||
|
*/
|
||||||
public Map<UUID, Double> getWeights() {
|
public Map<UUID, Double> getWeights() {
|
||||||
return weights;
|
return weights;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@ public abstract class BackgroundJob<A> extends Job<A> {
|
|||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the job priority. */
|
/**
|
||||||
|
* @return the job priority.
|
||||||
|
*/
|
||||||
public int getPriority() {
|
public int getPriority() {
|
||||||
return priority;
|
return priority;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,7 @@ import org.enso.interpreter.runtime.data.text.Text;
|
|||||||
import org.enso.interpreter.runtime.error.WithWarnings;
|
import org.enso.interpreter.runtime.error.WithWarnings;
|
||||||
|
|
||||||
public final class VisualizationResult {
|
public final class VisualizationResult {
|
||||||
private VisualizationResult() {
|
private VisualizationResult() {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a string representation for a polyglot exception.
|
* Extracts a string representation for a polyglot exception.
|
||||||
|
@ -8,7 +8,9 @@ public class ExecutionTime implements ProfilingInfo {
|
|||||||
this.nanoTimeElapsed = nanoTimeElapsed;
|
this.nanoTimeElapsed = nanoTimeElapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the time elapsed while executing the expression */
|
/**
|
||||||
|
* @return the time elapsed while executing the expression
|
||||||
|
*/
|
||||||
public long getNanoTimeElapsed() {
|
public long getNanoTimeElapsed() {
|
||||||
return nanoTimeElapsed;
|
return nanoTimeElapsed;
|
||||||
}
|
}
|
||||||
@ -18,7 +20,9 @@ public class ExecutionTime implements ProfilingInfo {
|
|||||||
return "ExecutionTime{nanoTimeElapsed=" + nanoTimeElapsed + "}";
|
return "ExecutionTime{nanoTimeElapsed=" + nanoTimeElapsed + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return an execution time representing that no time has passed */
|
/**
|
||||||
|
* @return an execution time representing that no time has passed
|
||||||
|
*/
|
||||||
public static ExecutionTime empty() {
|
public static ExecutionTime empty() {
|
||||||
return new ExecutionTime(0);
|
return new ExecutionTime(0);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,19 @@
|
|||||||
package org.enso.interpreter.service;
|
package org.enso.interpreter.service;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CallTarget;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.TruffleLogger;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.instrumentation.EventBinding;
|
||||||
|
import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
|
||||||
|
import com.oracle.truffle.api.interop.ArityException;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -8,7 +22,6 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.enso.compiler.context.SimpleUpdate;
|
import org.enso.compiler.context.SimpleUpdate;
|
||||||
import org.enso.interpreter.instrument.Endpoint;
|
import org.enso.interpreter.instrument.Endpoint;
|
||||||
import org.enso.interpreter.instrument.MethodCallsCache;
|
import org.enso.interpreter.instrument.MethodCallsCache;
|
||||||
@ -47,21 +60,6 @@ import org.enso.polyglot.debugger.IdExecutionService;
|
|||||||
import org.enso.text.editing.JavaEditorAdapter;
|
import org.enso.text.editing.JavaEditorAdapter;
|
||||||
import org.enso.text.editing.model;
|
import org.enso.text.editing.model;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CallTarget;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.TruffleLogger;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.instrumentation.EventBinding;
|
|
||||||
import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
|
|
||||||
import com.oracle.truffle.api.interop.ArityException;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service allowing externally-triggered code execution, registered by an instance of the
|
* A service allowing externally-triggered code execution, registered by an instance of the
|
||||||
* language.
|
* language.
|
||||||
@ -72,7 +70,8 @@ public final class ExecutionService {
|
|||||||
private final EnsoContext context;
|
private final EnsoContext context;
|
||||||
private final Optional<IdExecutionService> idExecutionInstrument;
|
private final Optional<IdExecutionService> idExecutionInstrument;
|
||||||
private final NotificationHandler.Forwarder notificationForwarder;
|
private final NotificationHandler.Forwarder notificationForwarder;
|
||||||
private final TruffleLogger logger = TruffleLogger.getLogger(LanguageInfo.ID, ExecutionService.class);
|
private final TruffleLogger logger =
|
||||||
|
TruffleLogger.getLogger(LanguageInfo.ID, ExecutionService.class);
|
||||||
private final ConnectedLockManager connectedLockManager;
|
private final ConnectedLockManager connectedLockManager;
|
||||||
private final ExecuteRootNode execute = new ExecuteRootNode();
|
private final ExecuteRootNode execute = new ExecuteRootNode();
|
||||||
private final CallRootNode call = new CallRootNode();
|
private final CallRootNode call = new CallRootNode();
|
||||||
@ -103,12 +102,16 @@ public final class ExecutionService {
|
|||||||
this.timer = timer;
|
this.timer = timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the language context. */
|
/**
|
||||||
|
* @return the language context.
|
||||||
|
*/
|
||||||
public EnsoContext getContext() {
|
public EnsoContext getContext() {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the execution service logger. */
|
/**
|
||||||
|
* @return the execution service logger.
|
||||||
|
*/
|
||||||
public TruffleLogger getLogger() {
|
public TruffleLogger getLogger() {
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
@ -138,8 +141,8 @@ public final class ExecutionService {
|
|||||||
connectedLockManager.connect(endpoint);
|
connectedLockManager.connect(endpoint);
|
||||||
} else {
|
} else {
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"ConnectedLockManager was not initialized, even though a Language Server connection has been established. "
|
"ConnectedLockManager was not initialized, even though a Language Server connection has"
|
||||||
+ "This may result in synchronization errors.");
|
+ " been established. This may result in synchronization errors.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,8 +193,7 @@ public final class ExecutionService {
|
|||||||
Optional<EventBinding<ExecutionEventNodeFactory>> eventNodeFactory =
|
Optional<EventBinding<ExecutionEventNodeFactory>> eventNodeFactory =
|
||||||
idExecutionInstrument.map(
|
idExecutionInstrument.map(
|
||||||
service ->
|
service ->
|
||||||
service.bind(
|
service.bind(module, call.getFunction().getCallTarget(), callbacks, this.timer));
|
||||||
module, call.getFunction().getCallTarget(), callbacks, this.timer));
|
|
||||||
Object p = context.getThreadManager().enter();
|
Object p = context.getThreadManager().enter();
|
||||||
try {
|
try {
|
||||||
execute.getCallTarget().call(call);
|
execute.getCallTarget().call(call);
|
||||||
@ -402,7 +404,13 @@ public final class ExecutionService {
|
|||||||
module.getName(), edits, failure, module.getLiteralSource());
|
module.getName(), edits, failure, module.getLiteralSource());
|
||||||
},
|
},
|
||||||
rope -> {
|
rope -> {
|
||||||
logger.log(Level.FINE, "Applied edits. Source has {} lines, last line has {} characters", new Object[]{rope.lines().length(), rope.lines().drop(rope.lines().length() - 1).characters().length()});
|
logger.log(
|
||||||
|
Level.FINE,
|
||||||
|
"Applied edits. Source has {} lines, last line has {} characters",
|
||||||
|
new Object[] {
|
||||||
|
rope.lines().length(),
|
||||||
|
rope.lines().drop(rope.lines().length() - 1).characters().length()
|
||||||
|
});
|
||||||
module.setLiteralSource(rope, simpleUpdate);
|
module.setLiteralSource(rope, simpleUpdate);
|
||||||
return new Object();
|
return new Object();
|
||||||
});
|
});
|
||||||
@ -459,7 +467,8 @@ public final class ExecutionService {
|
|||||||
var iop = InteropLibrary.getUncached();
|
var iop = InteropLibrary.getUncached();
|
||||||
var p = context.getThreadManager().enter();
|
var p = context.getThreadManager().enter();
|
||||||
try {
|
try {
|
||||||
// Invoking a member on an Atom that does not have a method `to_display_text` will not contrary to what is
|
// Invoking a member on an Atom that does not have a method `to_display_text` will not
|
||||||
|
// contrary to what is
|
||||||
// expected from the documentation, throw an `UnsupportedMessageException`.
|
// expected from the documentation, throw an `UnsupportedMessageException`.
|
||||||
// Instead it will crash with some internal assertion deep inside runtime. Hence the check.
|
// Instead it will crash with some internal assertion deep inside runtime. Hence the check.
|
||||||
if (iop.isMemberInvocable(panic.getPayload(), "to_display_text")) {
|
if (iop.isMemberInvocable(panic.getPayload(), "to_display_text")) {
|
||||||
@ -487,8 +496,7 @@ public final class ExecutionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class ExecuteRootNode extends RootNode {
|
private static final class ExecuteRootNode extends RootNode {
|
||||||
@Node.Child
|
@Node.Child private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
||||||
private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
|
||||||
|
|
||||||
ExecuteRootNode() {
|
ExecuteRootNode() {
|
||||||
super(null);
|
super(null);
|
||||||
@ -508,8 +516,7 @@ public final class ExecutionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class CallRootNode extends RootNode {
|
private static final class CallRootNode extends RootNode {
|
||||||
@Node.Child
|
@Node.Child private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
||||||
private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
|
||||||
|
|
||||||
CallRootNode() {
|
CallRootNode() {
|
||||||
super(null);
|
super(null);
|
||||||
@ -528,8 +535,7 @@ public final class ExecutionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class InvokeMemberRootNode extends RootNode {
|
private static final class InvokeMemberRootNode extends RootNode {
|
||||||
@Node.Child
|
@Node.Child private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
||||||
private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(5);
|
|
||||||
|
|
||||||
InvokeMemberRootNode() {
|
InvokeMemberRootNode() {
|
||||||
super(null);
|
super(null);
|
||||||
@ -567,12 +573,16 @@ public final class ExecutionService {
|
|||||||
this.call = call;
|
this.call = call;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the id of the node performing the function call. */
|
/**
|
||||||
|
* @return the id of the node performing the function call.
|
||||||
|
*/
|
||||||
public UUID getExpressionId() {
|
public UUID getExpressionId() {
|
||||||
return expressionId;
|
return expressionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the function call metadata. */
|
/**
|
||||||
|
* @return the function call metadata.
|
||||||
|
*/
|
||||||
public FunctionCallInstrumentationNode.FunctionCall getCall() {
|
public FunctionCallInstrumentationNode.FunctionCall getCall() {
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
@ -645,52 +655,72 @@ public final class ExecutionService {
|
|||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the id of the expression computed. */
|
/**
|
||||||
|
* @return the id of the expression computed.
|
||||||
|
*/
|
||||||
public UUID getExpressionId() {
|
public UUID getExpressionId() {
|
||||||
return expressionId;
|
return expressionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the type of the returned value. */
|
/**
|
||||||
|
* @return the type of the returned value.
|
||||||
|
*/
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the cached type of the value. */
|
/**
|
||||||
|
* @return the cached type of the value.
|
||||||
|
*/
|
||||||
public String getCachedType() {
|
public String getCachedType() {
|
||||||
return cachedType;
|
return cachedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the computed value of the expression. */
|
/**
|
||||||
|
* @return the computed value of the expression.
|
||||||
|
*/
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the function call data. */
|
/**
|
||||||
|
* @return the function call data.
|
||||||
|
*/
|
||||||
public FunctionCallInfo getCallInfo() {
|
public FunctionCallInfo getCallInfo() {
|
||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the function call data previously associated with the expression. */
|
/**
|
||||||
|
* @return the function call data previously associated with the expression.
|
||||||
|
*/
|
||||||
public FunctionCallInfo getCachedCallInfo() {
|
public FunctionCallInfo getCachedCallInfo() {
|
||||||
return cachedCallInfo;
|
return cachedCallInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the profiling information associated with this expression */
|
/**
|
||||||
|
* @return the profiling information associated with this expression
|
||||||
|
*/
|
||||||
public ProfilingInfo[] getProfilingInfo() {
|
public ProfilingInfo[] getProfilingInfo() {
|
||||||
return profilingInfo;
|
return profilingInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return whether or not the expression result was obtained from the cache */
|
/**
|
||||||
|
* @return whether or not the expression result was obtained from the cache
|
||||||
|
*/
|
||||||
public boolean wasCached() {
|
public boolean wasCached() {
|
||||||
return wasCached;
|
return wasCached;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {@code true} when the type differs from the cached value. */
|
/**
|
||||||
|
* @return {@code true} when the type differs from the cached value.
|
||||||
|
*/
|
||||||
public boolean isTypeChanged() {
|
public boolean isTypeChanged() {
|
||||||
return !Objects.equals(type, cachedType);
|
return !Objects.equals(type, cachedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {@code true} when the function call differs from the cached value. */
|
/**
|
||||||
|
* @return {@code true} when the function call differs from the cached value.
|
||||||
|
*/
|
||||||
public boolean isFunctionCallChanged() {
|
public boolean isFunctionCallChanged() {
|
||||||
return !Objects.equals(callInfo, cachedCallInfo);
|
return !Objects.equals(callInfo, cachedCallInfo);
|
||||||
}
|
}
|
||||||
|
@ -102,9 +102,7 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut
|
|||||||
* @param materializedFrame the execution frame
|
* @param materializedFrame the execution frame
|
||||||
* @param node the entered node
|
* @param node the entered node
|
||||||
*/
|
*/
|
||||||
public NodeInfo(
|
public NodeInfo(MaterializedFrame materializedFrame, Node node) {
|
||||||
MaterializedFrame materializedFrame,
|
|
||||||
Node node) {
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.nodeId = getNodeId(node);
|
this.nodeId = getNodeId(node);
|
||||||
@ -243,7 +241,11 @@ public class IdExecutionInstrument extends TruffleInstrument implements IdExecut
|
|||||||
} else if (node instanceof ExpressionNode expressionNode) {
|
} else if (node instanceof ExpressionNode expressionNode) {
|
||||||
Info info =
|
Info info =
|
||||||
new NodeInfo(
|
new NodeInfo(
|
||||||
expressionNode.getId(), result, nanoTimeElapsed, frame == null ? null : frame.materialize(), node);
|
expressionNode.getId(),
|
||||||
|
result,
|
||||||
|
nanoTimeElapsed,
|
||||||
|
frame == null ? null : frame.materialize(),
|
||||||
|
node);
|
||||||
callbacks.updateCachedResult(info);
|
callbacks.updateCachedResult(info);
|
||||||
|
|
||||||
if (info.isPanic()) {
|
if (info.isPanic()) {
|
||||||
|
@ -1,26 +1,22 @@
|
|||||||
package org.enso.interpreter.instrument;
|
package org.enso.interpreter.instrument;
|
||||||
|
|
||||||
import org.enso.polyglot.debugger.IdExecutionService;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.TruffleContext;
|
import com.oracle.truffle.api.TruffleContext;
|
||||||
import com.oracle.truffle.api.instrumentation.ContextsListener;
|
import com.oracle.truffle.api.instrumentation.ContextsListener;
|
||||||
import com.oracle.truffle.api.instrumentation.EventBinding;
|
import com.oracle.truffle.api.instrumentation.EventBinding;
|
||||||
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
|
import com.oracle.truffle.api.instrumentation.TruffleInstrument;
|
||||||
import com.oracle.truffle.api.nodes.LanguageInfo;
|
import com.oracle.truffle.api.nodes.LanguageInfo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.enso.distribution.locking.LockManager;
|
import org.enso.distribution.locking.LockManager;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.service.ExecutionService;
|
import org.enso.interpreter.service.ExecutionService;
|
||||||
import org.enso.lockmanager.client.ConnectedLockManager;
|
import org.enso.lockmanager.client.ConnectedLockManager;
|
||||||
import org.enso.polyglot.RuntimeServerInfo;
|
import org.enso.polyglot.RuntimeServerInfo;
|
||||||
|
import org.enso.polyglot.debugger.IdExecutionService;
|
||||||
import org.graalvm.options.OptionDescriptor;
|
import org.graalvm.options.OptionDescriptor;
|
||||||
import org.graalvm.options.OptionDescriptors;
|
import org.graalvm.options.OptionDescriptors;
|
||||||
import org.graalvm.options.OptionKey;
|
|
||||||
import org.graalvm.polyglot.io.MessageEndpoint;
|
import org.graalvm.polyglot.io.MessageEndpoint;
|
||||||
import org.graalvm.polyglot.io.MessageTransport;
|
import org.graalvm.polyglot.io.MessageTransport;
|
||||||
|
|
||||||
@ -76,7 +72,11 @@ public class RuntimeServerInstrument extends TruffleInstrument {
|
|||||||
var timer = instrument.env.lookup(language, Timer.class);
|
var timer = instrument.env.lookup(language, Timer.class);
|
||||||
var notificationHandler =
|
var notificationHandler =
|
||||||
instrument.env.lookup(language, NotificationHandler.Forwarder.class);
|
instrument.env.lookup(language, NotificationHandler.Forwarder.class);
|
||||||
var connectedLockManager = instrument.env.lookup(language, LockManager.class) instanceof ConnectedLockManager connected ? connected : null;
|
var connectedLockManager =
|
||||||
|
instrument.env.lookup(language, LockManager.class)
|
||||||
|
instanceof ConnectedLockManager connected
|
||||||
|
? connected
|
||||||
|
: null;
|
||||||
service =
|
service =
|
||||||
new ExecutionService(
|
new ExecutionService(
|
||||||
ctx, idExecutionInstrument, notificationHandler, connectedLockManager, timer);
|
ctx, idExecutionInstrument, notificationHandler, connectedLockManager, timer);
|
||||||
@ -141,7 +141,8 @@ public class RuntimeServerInstrument extends TruffleInstrument {
|
|||||||
protected OptionDescriptors getOptionDescriptors() {
|
protected OptionDescriptors getOptionDescriptors() {
|
||||||
return OptionDescriptors.create(
|
return OptionDescriptors.create(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
OptionDescriptor.newBuilder(RuntimeServerInfo.ENABLE_OPTION_KEY, RuntimeServerInfo.ENABLE_OPTION)
|
OptionDescriptor.newBuilder(
|
||||||
|
RuntimeServerInfo.ENABLE_OPTION_KEY, RuntimeServerInfo.ENABLE_OPTION)
|
||||||
.build()));
|
.build()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,9 @@ final class EpbContext {
|
|||||||
return REFERENCE.get(node);
|
return REFERENCE.get(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the language environment associated with this context. */
|
/**
|
||||||
|
* @return the language environment associated with this context.
|
||||||
|
*/
|
||||||
public TruffleLanguage.Env getEnv() {
|
public TruffleLanguage.Env getEnv() {
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
package org.enso.interpreter.epb;
|
package org.enso.interpreter.epb;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CallTarget;
|
import com.oracle.truffle.api.CallTarget;
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
@ -13,6 +7,11 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.interop.InteropException;
|
import com.oracle.truffle.api.interop.InteropException;
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
final class ForeignEvalNode extends RootNode {
|
final class ForeignEvalNode extends RootNode {
|
||||||
private final Source langAndCode;
|
private final Source langAndCode;
|
||||||
@ -58,20 +57,25 @@ final class ForeignEvalNode extends RootNode {
|
|||||||
var id = truffleId(langAndCode);
|
var id = truffleId(langAndCode);
|
||||||
var context = EpbContext.get(this);
|
var context = EpbContext.get(this);
|
||||||
var installedLanguages = context.getEnv().getInternalLanguages();
|
var installedLanguages = context.getEnv().getInternalLanguages();
|
||||||
var node = switch (installedLanguages.containsKey(id) ? 1 : 0) {
|
var node =
|
||||||
case 0 -> {
|
switch (installedLanguages.containsKey(id) ? 1 : 0) {
|
||||||
var ex = new ForeignParsingException(id, installedLanguages.keySet(), this);
|
case 0 -> {
|
||||||
yield new ExceptionForeignNode(ex);
|
var ex = new ForeignParsingException(id, installedLanguages.keySet(), this);
|
||||||
}
|
yield new ExceptionForeignNode(ex);
|
||||||
default -> {
|
}
|
||||||
context.log(Level.FINE, "Parsing foreign script {1} - language {0}", id, langAndCode.getName());
|
default -> {
|
||||||
yield switch (id) {
|
context.log(
|
||||||
case "js" -> parseJs();
|
Level.FINE,
|
||||||
case "python" -> parseGeneric("python", PyForeignNode::new);
|
"Parsing foreign script {1} - language {0}",
|
||||||
default -> parseGeneric(id, GenericForeignNode::new);
|
id,
|
||||||
|
langAndCode.getName());
|
||||||
|
yield switch (id) {
|
||||||
|
case "js" -> parseJs();
|
||||||
|
case "python" -> parseGeneric("python", PyForeignNode::new);
|
||||||
|
default -> parseGeneric(id, GenericForeignNode::new);
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
foreign = insert(node);
|
foreign = insert(node);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -87,20 +91,17 @@ final class ForeignEvalNode extends RootNode {
|
|||||||
var inner = context.getInnerContext();
|
var inner = context.getInnerContext();
|
||||||
var code = foreignSource(langAndCode);
|
var code = foreignSource(langAndCode);
|
||||||
var args = Arrays.stream(argNames).skip(1).collect(Collectors.joining(","));
|
var args = Arrays.stream(argNames).skip(1).collect(Collectors.joining(","));
|
||||||
var wrappedSrc
|
var wrappedSrc = "var poly_enso_eval=function(" + args + "){\n" + code + "\n};poly_enso_eval";
|
||||||
= "var poly_enso_eval=function("
|
|
||||||
+ args
|
|
||||||
+ "){\n"
|
|
||||||
+ code
|
|
||||||
+ "\n};poly_enso_eval";
|
|
||||||
Source source = Source.newBuilder("js", wrappedSrc, "").build();
|
Source source = Source.newBuilder("js", wrappedSrc, "").build();
|
||||||
var fn = inner.evalPublic(this, source);
|
var fn = inner.evalPublic(this, source);
|
||||||
return JsForeignNode.build(fn);
|
return JsForeignNode.build(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ForeignFunctionCallNode parseGeneric(String language, Function<CallTarget,ForeignFunctionCallNode> nodeFactory) {
|
private ForeignFunctionCallNode parseGeneric(
|
||||||
|
String language, Function<CallTarget, ForeignFunctionCallNode> nodeFactory) {
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
Source source = Source.newBuilder(language, foreignSource(langAndCode), langAndCode.getName()).build();
|
Source source =
|
||||||
|
Source.newBuilder(language, foreignSource(langAndCode), langAndCode.getName()).build();
|
||||||
CallTarget ct = ctx.getEnv().parsePublic(source, argNames);
|
CallTarget ct = ctx.getEnv().parsePublic(source, argNames);
|
||||||
return nodeFactory.apply(ct);
|
return nodeFactory.apply(ct);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
package org.enso.interpreter.epb;
|
package org.enso.interpreter.epb;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CallTarget;
|
import com.oracle.truffle.api.CallTarget;
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.interop.ArityException;
|
import com.oracle.truffle.api.interop.ArityException;
|
||||||
@ -17,28 +13,21 @@ import com.oracle.truffle.api.library.CachedLibrary;
|
|||||||
import com.oracle.truffle.api.library.ExportLibrary;
|
import com.oracle.truffle.api.library.ExportLibrary;
|
||||||
import com.oracle.truffle.api.library.ExportMessage;
|
import com.oracle.truffle.api.library.ExportMessage;
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
final class PyForeignNode extends GenericForeignNode {
|
final class PyForeignNode extends GenericForeignNode {
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private Object fnPythonDate;
|
||||||
private Object fnPythonDate;
|
@Child private InteropLibrary nodePythonDate;
|
||||||
@Child
|
@CompilerDirectives.CompilationFinal private Object fnPythonTime;
|
||||||
private InteropLibrary nodePythonDate;
|
@Child private InteropLibrary nodePythonTime;
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private Object fnPythonZone;
|
||||||
private Object fnPythonTime;
|
@Child private InteropLibrary nodePythonZone;
|
||||||
@Child
|
@CompilerDirectives.CompilationFinal private Object fnPythonCombine;
|
||||||
private InteropLibrary nodePythonTime;
|
@CompilerDirectives.CompilationFinal private Object none;
|
||||||
@CompilerDirectives.CompilationFinal
|
@Child private InteropLibrary nodePythonCombine;
|
||||||
private Object fnPythonZone;
|
@Child private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(3);
|
||||||
@Child
|
|
||||||
private InteropLibrary nodePythonZone;
|
|
||||||
@CompilerDirectives.CompilationFinal
|
|
||||||
private Object fnPythonCombine;
|
|
||||||
@CompilerDirectives.CompilationFinal
|
|
||||||
private Object none;
|
|
||||||
@Child
|
|
||||||
private InteropLibrary nodePythonCombine;
|
|
||||||
@Child
|
|
||||||
private InteropLibrary iop = InteropLibrary.getFactory().createDispatched(3);
|
|
||||||
|
|
||||||
PyForeignNode(CallTarget ct) {
|
PyForeignNode(CallTarget ct) {
|
||||||
super(ct);
|
super(ct);
|
||||||
@ -54,7 +43,10 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
var time = javaTime != null ? wrapPythonTime(javaTime) : null;
|
var time = javaTime != null ? wrapPythonTime(javaTime) : null;
|
||||||
var javaDate = iop.isDate(arguments[i]) ? iop.asDate(arguments[i]) : null;
|
var javaDate = iop.isDate(arguments[i]) ? iop.asDate(arguments[i]) : null;
|
||||||
var date = javaDate != null ? wrapPythonDate(javaDate) : null;
|
var date = javaDate != null ? wrapPythonDate(javaDate) : null;
|
||||||
var zone = iop.isTimeZone(arguments[i]) ? wrapPythonZone(iop.asTimeZone(arguments[i]), javaTime, javaDate) : null;
|
var zone =
|
||||||
|
iop.isTimeZone(arguments[i])
|
||||||
|
? wrapPythonZone(iop.asTimeZone(arguments[i]), javaTime, javaDate)
|
||||||
|
: null;
|
||||||
if (date != null && time != null) {
|
if (date != null && time != null) {
|
||||||
arguments[i] = combinePythonDateTimeZone(date, time, zone);
|
arguments[i] = combinePythonDateTimeZone(date, time, zone);
|
||||||
} else if (date != null) {
|
} else if (date != null) {
|
||||||
@ -82,16 +74,22 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object none() throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
private Object none()
|
||||||
|
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
||||||
if (none == null) {
|
if (none == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
var src = Source.newBuilder("python", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"python",
|
||||||
|
"""
|
||||||
import site
|
import site
|
||||||
def nothing():
|
def nothing():
|
||||||
return None
|
return None
|
||||||
nothing
|
nothing
|
||||||
""", "nothing.py").build();
|
""",
|
||||||
|
"nothing.py")
|
||||||
|
.build();
|
||||||
var nothingFn = ctx.getEnv().parsePublic(src).call();
|
var nothingFn = ctx.getEnv().parsePublic(src).call();
|
||||||
assert InteropLibrary.getUncached().isExecutable(nothingFn);
|
assert InteropLibrary.getUncached().isExecutable(nothingFn);
|
||||||
none = InteropLibrary.getUncached().execute(nothingFn);
|
none = InteropLibrary.getUncached().execute(nothingFn);
|
||||||
@ -100,41 +98,58 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object wrapPythonDate(LocalDate date) throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
private Object wrapPythonDate(LocalDate date)
|
||||||
|
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
||||||
if (nodePythonDate == null) {
|
if (nodePythonDate == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
var src = Source.newBuilder("python", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"python",
|
||||||
|
"""
|
||||||
from datetime import date
|
from datetime import date
|
||||||
date
|
date
|
||||||
""", "convert_date.py").build();
|
""",
|
||||||
|
"convert_date.py")
|
||||||
|
.build();
|
||||||
|
|
||||||
fnPythonDate = ctx.getEnv().parsePublic(src).call();
|
fnPythonDate = ctx.getEnv().parsePublic(src).call();
|
||||||
nodePythonDate = insert(InteropLibrary.getFactory().create(fnPythonDate));
|
nodePythonDate = insert(InteropLibrary.getFactory().create(fnPythonDate));
|
||||||
}
|
}
|
||||||
return nodePythonDate.execute(fnPythonDate, date.getYear(), date.getMonthValue(), date.getDayOfMonth());
|
return nodePythonDate.execute(
|
||||||
|
fnPythonDate, date.getYear(), date.getMonthValue(), date.getDayOfMonth());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object wrapPythonTime(LocalTime time) throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
private Object wrapPythonTime(LocalTime time)
|
||||||
|
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
||||||
if (nodePythonTime == null) {
|
if (nodePythonTime == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
var src = Source.newBuilder("python", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"python",
|
||||||
|
"""
|
||||||
from datetime import time
|
from datetime import time
|
||||||
time
|
time
|
||||||
""", "convert_time.py").build();
|
""",
|
||||||
|
"convert_time.py")
|
||||||
|
.build();
|
||||||
fnPythonTime = ctx.getEnv().parsePublic(src).call();
|
fnPythonTime = ctx.getEnv().parsePublic(src).call();
|
||||||
nodePythonTime = insert(InteropLibrary.getFactory().create(fnPythonTime));
|
nodePythonTime = insert(InteropLibrary.getFactory().create(fnPythonTime));
|
||||||
}
|
}
|
||||||
return nodePythonTime.execute(fnPythonTime, time.getHour(), time.getMinute(), time.getSecond(), time.getNano() / 1000);
|
return nodePythonTime.execute(
|
||||||
|
fnPythonTime, time.getHour(), time.getMinute(), time.getSecond(), time.getNano() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object wrapPythonZone(ZoneId zone, LocalTime time, LocalDate date)
|
private Object wrapPythonZone(ZoneId zone, LocalTime time, LocalDate date)
|
||||||
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
if (nodePythonZone == null) {
|
if (nodePythonZone == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
var src = Source.newBuilder("python", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"python",
|
||||||
|
"""
|
||||||
from datetime import timezone, timedelta, tzinfo
|
from datetime import timezone, timedelta, tzinfo
|
||||||
|
|
||||||
class EnsoTzInfo(tzinfo):
|
class EnsoTzInfo(tzinfo):
|
||||||
@ -156,7 +171,9 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
return EnsoTzInfo(rules)
|
return EnsoTzInfo(rules)
|
||||||
|
|
||||||
conv
|
conv
|
||||||
""", "convert_time_zone.py").build();
|
""",
|
||||||
|
"convert_time_zone.py")
|
||||||
|
.build();
|
||||||
|
|
||||||
fnPythonZone = ctx.getEnv().parsePublic(src).call();
|
fnPythonZone = ctx.getEnv().parsePublic(src).call();
|
||||||
nodePythonZone = insert(InteropLibrary.getFactory().create(fnPythonZone));
|
nodePythonZone = insert(InteropLibrary.getFactory().create(fnPythonZone));
|
||||||
@ -165,14 +182,19 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Object combinePythonDateTimeZone(Object date, Object time, Object zone)
|
private Object combinePythonDateTimeZone(Object date, Object time, Object zone)
|
||||||
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
throws UnsupportedTypeException, ArityException, UnsupportedMessageException {
|
||||||
if (nodePythonCombine == null) {
|
if (nodePythonCombine == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
var ctx = EpbContext.get(this);
|
var ctx = EpbContext.get(this);
|
||||||
var src = Source.newBuilder("python", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"python",
|
||||||
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
datetime.combine
|
datetime.combine
|
||||||
""", "convert_combine.py").build();
|
""",
|
||||||
|
"convert_combine.py")
|
||||||
|
.build();
|
||||||
|
|
||||||
fnPythonCombine = ctx.getEnv().parsePublic(src).call();
|
fnPythonCombine = ctx.getEnv().parsePublic(src).call();
|
||||||
nodePythonCombine = insert(InteropLibrary.getFactory().create(fnPythonCombine));
|
nodePythonCombine = insert(InteropLibrary.getFactory().create(fnPythonCombine));
|
||||||
@ -202,10 +224,8 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
@ExportMessage
|
@ExportMessage
|
||||||
boolean isMemberInvocable(String member) {
|
boolean isMemberInvocable(String member) {
|
||||||
return switch (member) {
|
return switch (member) {
|
||||||
case "dst", "name", "offset" ->
|
case "dst", "name", "offset" -> true;
|
||||||
true;
|
default -> false;
|
||||||
default ->
|
|
||||||
false;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,10 +236,8 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
Object invokeMember(
|
Object invokeMember(String name, Object[] args, @CachedLibrary(limit = "3") InteropLibrary iop)
|
||||||
String name, Object[] args,
|
throws UnknownIdentifierException, UnsupportedMessageException {
|
||||||
@CachedLibrary(limit = "3") InteropLibrary iop
|
|
||||||
) throws UnknownIdentifierException, UnsupportedMessageException {
|
|
||||||
var date = iop.asDate(args[0]);
|
var date = iop.asDate(args[0]);
|
||||||
var time = iop.asTime(args[0]);
|
var time = iop.asTime(args[0]);
|
||||||
var when = date.atTime(time);
|
var when = date.atTime(time);
|
||||||
@ -231,10 +249,8 @@ final class PyForeignNode extends GenericForeignNode {
|
|||||||
yield now.getTotalSeconds() - std.getTotalSeconds();
|
yield now.getTotalSeconds() - std.getTotalSeconds();
|
||||||
}
|
}
|
||||||
case "name" -> zone.getId();
|
case "name" -> zone.getId();
|
||||||
case "offset" ->
|
case "offset" -> zone.getRules().getOffset(when).getTotalSeconds();
|
||||||
zone.getRules().getOffset(when).getTotalSeconds();
|
default -> throw UnknownIdentifierException.create(name);
|
||||||
default ->
|
|
||||||
throw UnknownIdentifierException.create(name);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
package org.enso.interpreter.epb;
|
package org.enso.interpreter.epb;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ForeignEvalNodeTest {
|
public class ForeignEvalNodeTest {
|
||||||
|
|
||||||
public ForeignEvalNodeTest() {
|
public ForeignEvalNodeTest() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sourceWithoutHash() throws Exception {
|
public void sourceWithoutHash() throws Exception {
|
||||||
|
@ -5,41 +5,44 @@ import scala.Option;
|
|||||||
|
|
||||||
public record IdentifiedLocation(Location location, UUID uuid) {
|
public record IdentifiedLocation(Location location, UUID uuid) {
|
||||||
public IdentifiedLocation(Location location) {
|
public IdentifiedLocation(Location location) {
|
||||||
this(location, (UUID)null);
|
this(location, (UUID) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates new location from an optional UUID. */
|
||||||
* Creates new location from an optional UUID.
|
|
||||||
*/
|
|
||||||
public static IdentifiedLocation create(Location location, Option<UUID> uuid) {
|
public static IdentifiedLocation create(Location location, Option<UUID> uuid) {
|
||||||
return new IdentifiedLocation(location, uuid.isEmpty() ? null : uuid.get());
|
return new IdentifiedLocation(location, uuid.isEmpty() ? null : uuid.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the character index of the start of this source location.
|
/**
|
||||||
*/
|
* @return the character index of the start of this source location.
|
||||||
|
*/
|
||||||
public int start() {
|
public int start() {
|
||||||
return location().start();
|
return location().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the character index of the end of this source location.
|
/**
|
||||||
*/
|
* @return the character index of the end of this source location.
|
||||||
|
*/
|
||||||
public int end() {
|
public int end() {
|
||||||
return location().end();
|
return location().end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the length in characters of this location.
|
/**
|
||||||
*/
|
* @return the length in characters of this location.
|
||||||
|
*/
|
||||||
public int length() {
|
public int length() {
|
||||||
return location().length();
|
return location().length();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return option with/out UUID */
|
/**
|
||||||
|
* @return option with/out UUID
|
||||||
|
*/
|
||||||
public Option<UUID> id() {
|
public Option<UUID> id() {
|
||||||
return Option.apply(uuid());
|
return Option.apply(uuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "IdentifiedLocation[location=" + this.location() + ", uuid="+ id() + "]";
|
return "IdentifiedLocation[location=" + this.location() + ", uuid=" + id() + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,9 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.enso.persist.Persistance;
|
import org.enso.persist.Persistance;
|
||||||
import org.enso.persist.Persistance.Reference;
|
import org.enso.persist.Persistance.Reference;
|
||||||
|
|
||||||
|
|
||||||
final class IrLazyMap<K, V> extends AbstractMap<K, V> {
|
final class IrLazyMap<K, V> extends AbstractMap<K, V> {
|
||||||
private final Map<K, Entry<K, V>> delegate;
|
private final Map<K, Entry<K, V>> delegate;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package org.enso.compiler.core.ir;
|
|||||||
|
|
||||||
import org.enso.persist.Persistable;
|
import org.enso.persist.Persistable;
|
||||||
|
|
||||||
@Persistable(clazz=Location.class, id=1)
|
@Persistable(clazz = Location.class, id = 1)
|
||||||
public record Location(int start, int end) {
|
public record Location(int start, int end) {
|
||||||
public int length() {
|
public int length() {
|
||||||
return end - start;
|
return end - start;
|
||||||
|
@ -10,13 +10,10 @@ import java.util.Objects;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.enso.compiler.core.CompilerStub;
|
import org.enso.compiler.core.CompilerStub;
|
||||||
|
|
||||||
import scala.Option;
|
import scala.Option;
|
||||||
|
|
||||||
/** Stores metadata for the various passes.
|
/** Stores metadata for the various passes. */
|
||||||
*/
|
|
||||||
public final class MetadataStorage {
|
public final class MetadataStorage {
|
||||||
private Map<ProcessingPass, ProcessingPass.Metadata> metadata;
|
private Map<ProcessingPass, ProcessingPass.Metadata> metadata;
|
||||||
|
|
||||||
@ -28,37 +25,40 @@ public final class MetadataStorage {
|
|||||||
this.metadata = init;
|
this.metadata = init;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds a new metadata entity to the pass metadata, or updates it if it
|
/**
|
||||||
* already exists for a given pass.
|
* Adds a new metadata entity to the pass metadata, or updates it if it already exists for a given
|
||||||
*
|
* pass.
|
||||||
* @param pass the pass to add the metadata for
|
*
|
||||||
* @param newMeta the metadata to add for `pass`
|
* @param pass the pass to add the metadata for
|
||||||
* @tparam K the concrete type of `pass`
|
* @param newMeta the metadata to add for `pass`
|
||||||
*/
|
* @tparam K the concrete type of `pass`
|
||||||
|
*/
|
||||||
public void update(ProcessingPass pass, ProcessingPass.Metadata newMeta) {
|
public void update(ProcessingPass pass, ProcessingPass.Metadata newMeta) {
|
||||||
var copy = copyMetaMap();
|
var copy = copyMetaMap();
|
||||||
copy.put(pass, newMeta);
|
copy.put(pass, newMeta);
|
||||||
metadata = copy;
|
metadata = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adds a metadata pair to the node metadata.
|
/**
|
||||||
*
|
* Adds a metadata pair to the node metadata.
|
||||||
* This will overwrite any entry whose key matches [[MetadataPair#pass]].
|
*
|
||||||
*
|
* <p>This will overwrite any entry whose key matches [[MetadataPair#pass]].
|
||||||
* @param <K> the concrete type of the pass
|
*
|
||||||
* @param metadataPair the pair to add to the storage
|
* @param <K> the concrete type of the pass
|
||||||
*/
|
* @param metadataPair the pair to add to the storage
|
||||||
|
*/
|
||||||
public <K extends ProcessingPass> void update(MetadataPair<K> metadataPair) {
|
public <K extends ProcessingPass> void update(MetadataPair<K> metadataPair) {
|
||||||
update(metadataPair.pass(), metadataPair.metadata());
|
update(metadataPair.pass(), metadataPair.metadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Removes the metadata for the specified pass from the list.
|
/**
|
||||||
*
|
* Removes the metadata for the specified pass from the list.
|
||||||
* @param pass the pass to remove metadata for
|
*
|
||||||
* @tparam K the concrete type of `pass`
|
* @param pass the pass to remove metadata for
|
||||||
* @return the removed metadata for that pass, if it exists
|
* @tparam K the concrete type of `pass`
|
||||||
*/
|
* @return the removed metadata for that pass, if it exists
|
||||||
public Option<ProcessingPass.Metadata> remove(ProcessingPass pass) {
|
*/
|
||||||
|
public Option<ProcessingPass.Metadata> remove(ProcessingPass pass) {
|
||||||
var prev = metadata.get(pass);
|
var prev = metadata.get(pass);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
return Option.empty();
|
return Option.empty();
|
||||||
@ -68,23 +68,25 @@ public final class MetadataStorage {
|
|||||||
metadata = copy;
|
metadata = copy;
|
||||||
return Option.apply(prev);
|
return Option.apply(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the metadata for the specified pass.
|
/**
|
||||||
*
|
* Gets the metadata for the specified pass.
|
||||||
* @param pass the pass to get the metadata for
|
*
|
||||||
* @tparam K the concrete type of `pass`
|
* @param pass the pass to get the metadata for
|
||||||
* @return the metadata for `pass`, if it exists
|
* @tparam K the concrete type of `pass`
|
||||||
*/
|
* @return the metadata for `pass`, if it exists
|
||||||
|
*/
|
||||||
public Option<ProcessingPass.Metadata> get(ProcessingPass pass) {
|
public Option<ProcessingPass.Metadata> get(ProcessingPass pass) {
|
||||||
var prev = (ProcessingPass.Metadata) metadata.get(pass);
|
var prev = (ProcessingPass.Metadata) metadata.get(pass);
|
||||||
return Option.apply(prev);
|
return Option.apply(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a deep copy of `this`.
|
/**
|
||||||
*
|
* Creates a deep copy of `this`.
|
||||||
* @return a deep copy of `this`
|
*
|
||||||
*/
|
* @return a deep copy of `this`
|
||||||
|
*/
|
||||||
public MetadataStorage duplicate() {
|
public MetadataStorage duplicate() {
|
||||||
var map = new HashMap<ProcessingPass, ProcessingPass.Metadata>();
|
var map = new HashMap<ProcessingPass, ProcessingPass.Metadata>();
|
||||||
for (var entry : this.metadata.entrySet()) {
|
for (var entry : this.metadata.entrySet()) {
|
||||||
@ -99,65 +101,72 @@ public final class MetadataStorage {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/** Maps across the stored metadata, transforming it to an output list.
|
* Maps across the stored metadata, transforming it to an output list.
|
||||||
*
|
*
|
||||||
* @param <R> the resulting element of the list
|
* @param <R> the resulting element of the list
|
||||||
* @param fn the function to apply over the metadata
|
* @param fn the function to apply over the metadata
|
||||||
* @return a list containing the results of transforming the metadata storage
|
* @return a list containing the results of transforming the metadata storage
|
||||||
*/
|
*/
|
||||||
public <R> List<R> map(BiFunction<ProcessingPass, ProcessingPass.Metadata, R> fn) {
|
public <R> List<R> map(BiFunction<ProcessingPass, ProcessingPass.Metadata, R> fn) {
|
||||||
return metadata.entrySet().stream().map(
|
return metadata.entrySet().stream().map((en) -> fn.apply(en.getKey(), en.getValue())).toList();
|
||||||
(en) -> fn.apply(en.getKey(), en.getValue())
|
|
||||||
).toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prepares the metadata for serialization.
|
/**
|
||||||
*
|
* Prepares the metadata for serialization.
|
||||||
* This operation takes place _in place_.
|
*
|
||||||
*
|
* <p>This operation takes place _in place_.
|
||||||
* Metadata prepared for serialization should not contain any links that
|
*
|
||||||
* span more than one module, or any other properties that are problematic
|
* <p>Metadata prepared for serialization should not contain any links that span more than one
|
||||||
* when serialized.
|
* module, or any other properties that are problematic when serialized.
|
||||||
*
|
*
|
||||||
* Due to the type safety properties of
|
* <p>Due to the type safety properties of [[org.enso.compiler.core.ir.MetadataStorage]], to allow
|
||||||
* [[org.enso.compiler.core.ir.MetadataStorage]], to allow this conversion
|
* this conversion to work it must be type-refined to return `typeof this`. To that end, there is
|
||||||
* to work it must be type-refined to return `typeof this`. To that end,
|
* no default definition for this method.
|
||||||
* there is no default definition for this method.
|
*
|
||||||
*
|
* @param compiler the Enso compiler
|
||||||
* @param compiler the Enso compiler
|
*/
|
||||||
*/
|
|
||||||
public final void prepareForSerialization(CompilerStub compiler) {
|
public final void prepareForSerialization(CompilerStub compiler) {
|
||||||
var newMap = metadata.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, (en) -> {
|
var newMap =
|
||||||
var value = en.getValue();
|
metadata.entrySet().stream()
|
||||||
var newVal = value.prepareForSerialization(compiler);
|
.collect(
|
||||||
return newVal;
|
Collectors.toMap(
|
||||||
}));
|
Map.Entry::getKey,
|
||||||
|
(en) -> {
|
||||||
|
var value = en.getValue();
|
||||||
|
var newVal = value.prepareForSerialization(compiler);
|
||||||
|
return newVal;
|
||||||
|
}));
|
||||||
this.metadata.putAll(newMap);
|
this.metadata.putAll(newMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Restores metadata after it has been deserialized.
|
/**
|
||||||
*
|
* Restores metadata after it has been deserialized.
|
||||||
* Due to the type safety properties of
|
*
|
||||||
* [[org.enso.compiler.core.ir.MetadataStorage]], to allow this conversion
|
* <p>Due to the type safety properties of [[org.enso.compiler.core.ir.MetadataStorage]], to allow
|
||||||
* to work it must be type-refined to return `typeof this`. To that end,
|
* this conversion to work it must be type-refined to return `typeof this`. To that end, there is
|
||||||
* there is no default definition for this method.
|
* no default definition for this method.
|
||||||
*
|
*
|
||||||
* @param compiler the Enso compiler
|
* @param compiler the Enso compiler
|
||||||
* @return `true` if restoration was successful, `false` otherwise
|
* @return `true` if restoration was successful, `false` otherwise
|
||||||
*/
|
*/
|
||||||
public boolean restoreFromSerialization(CompilerStub compiler) {
|
public boolean restoreFromSerialization(CompilerStub compiler) {
|
||||||
var ok = new boolean[] { true };
|
var ok = new boolean[] {true};
|
||||||
var newMap = metadata.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, (en) -> {
|
var newMap =
|
||||||
var value = en.getValue();
|
metadata.entrySet().stream()
|
||||||
var newOption = value.restoreFromSerialization(compiler);
|
.collect(
|
||||||
if (newOption.nonEmpty()) {
|
Collectors.toMap(
|
||||||
return newOption.get();
|
Map.Entry::getKey,
|
||||||
} else {
|
(en) -> {
|
||||||
ok[0] = false;
|
var value = en.getValue();
|
||||||
return value;
|
var newOption = value.restoreFromSerialization(compiler);
|
||||||
}
|
if (newOption.nonEmpty()) {
|
||||||
}));
|
return newOption.get();
|
||||||
|
} else {
|
||||||
|
ok[0] = false;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}));
|
||||||
this.metadata = newMap;
|
this.metadata = newMap;
|
||||||
return ok[0];
|
return ok[0];
|
||||||
}
|
}
|
||||||
@ -181,9 +190,10 @@ public final class MetadataStorage {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Comparator<ProcessingPass> COMPARATOR = (p1, p2) -> {
|
private static final Comparator<ProcessingPass> COMPARATOR =
|
||||||
return p1.getClass().getName().compareTo(p2.getClass().getName());
|
(p1, p2) -> {
|
||||||
};
|
return p1.getClass().getName().compareTo(p2.getClass().getName());
|
||||||
|
};
|
||||||
|
|
||||||
private Map<ProcessingPass, ProcessingPass.Metadata> copyMetaMap() {
|
private Map<ProcessingPass, ProcessingPass.Metadata> copyMetaMap() {
|
||||||
var copy = new TreeMap<ProcessingPass, ProcessingPass.Metadata>(COMPARATOR);
|
var copy = new TreeMap<ProcessingPass, ProcessingPass.Metadata>(COMPARATOR);
|
||||||
@ -209,6 +219,5 @@ public final class MetadataStorage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record MetadataPair<K extends ProcessingPass> (K pass, ProcessingPass.Metadata metadata) {
|
public record MetadataPair<K extends ProcessingPass>(K pass, ProcessingPass.Metadata metadata) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package org.enso.compiler.core;
|
package org.enso.compiler.core;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.enso.compiler.core.ir.Module;
|
import org.enso.compiler.core.ir.Module;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -29,8 +29,7 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void closeEnsoParser() throws Exception {
|
public static void closeEnsoParser() throws Exception {
|
||||||
if (ensoCompiler != null)
|
if (ensoCompiler != null) ensoCompiler.close();
|
||||||
ensoCompiler.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -56,23 +55,31 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationsCorrectAssignmentOfVariableReads() throws Exception {
|
public void testLocationsCorrectAssignmentOfVariableReads() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
main =
|
main =
|
||||||
x = 2 + 2 * 2
|
x = 2 + 2 * 2
|
||||||
y = x * x
|
y = x * x
|
||||||
IO.println y
|
IO.println y
|
||||||
""", true, true, true);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationsMethodWithComplexBody() throws Exception {
|
public void testLocationsMethodWithComplexBody() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
foo a b =
|
foo a b =
|
||||||
x : Number
|
x : Number
|
||||||
x = a + 1
|
x = a + 1
|
||||||
y = b - 2
|
y = b - 2
|
||||||
x * y
|
x * y
|
||||||
""", true, true, true);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -101,12 +108,16 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationsDeeplyNestedFunctionsNoBlock() throws Exception {
|
public void testLocationsDeeplyNestedFunctionsNoBlock() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
Nothing.method =
|
Nothing.method =
|
||||||
add = a -> b -> a + b
|
add = a -> b -> a + b
|
||||||
|
|
||||||
main = Nothing.method
|
main = Nothing.method
|
||||||
""", true, true, true);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -119,7 +130,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCase() throws Exception {
|
public void testCase() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Msg
|
type Msg
|
||||||
Ahoj
|
Ahoj
|
||||||
Ciao
|
Ciao
|
||||||
@ -128,24 +140,24 @@ public class EnsoParserTest {
|
|||||||
Ahoj -> 0
|
Ahoj -> 0
|
||||||
Ciao -> 1
|
Ciao -> 1
|
||||||
Msg.Ciao -> 2
|
Msg.Ciao -> 2
|
||||||
"""
|
""");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTypeMethodWithSignature() throws Exception {
|
public void testTypeMethodWithSignature() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
@Builtin_Type
|
@Builtin_Type
|
||||||
type Fuzzy
|
type Fuzzy
|
||||||
== : Correct -> Wrong
|
== : Correct -> Wrong
|
||||||
== self right = @Builtin_Method "Fuzzy.=="
|
== self right = @Builtin_Method "Fuzzy.=="
|
||||||
"""
|
""");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImport() throws Exception {
|
public void testImport() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
import Standard.Base.Any.Any
|
import Standard.Base.Any.Any
|
||||||
import project.IO
|
import project.IO
|
||||||
import Standard.Base as Enso_List
|
import Standard.Base as Enso_List
|
||||||
@ -159,7 +171,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImportAll() throws Exception {
|
public void testImportAll() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
## TODO Dubious constructor export
|
## TODO Dubious constructor export
|
||||||
from project.Network.Http.Version.Version import all
|
from project.Network.Http.Version.Version import all
|
||||||
from project.Network.Http.Version.Version export all
|
from project.Network.Http.Version.Version export all
|
||||||
@ -297,7 +310,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBoolean() throws Exception {
|
public void testBoolean() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
@Builtin_Type
|
@Builtin_Type
|
||||||
type Boolean
|
type Boolean
|
||||||
True
|
True
|
||||||
@ -348,7 +362,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAtEq() throws Exception {
|
public void testAtEq() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Array
|
type Array
|
||||||
== : Array -> Boolean
|
== : Array -> Boolean
|
||||||
== self that =
|
== self that =
|
||||||
@ -360,7 +375,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNestedBlocks() throws Exception {
|
public void testNestedBlocks() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Array
|
type Array
|
||||||
meaning =
|
meaning =
|
||||||
catch_primitive handler
|
catch_primitive handler
|
||||||
@ -387,7 +403,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMetadataRaw() throws Exception {
|
public void testMetadataRaw() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
main =
|
main =
|
||||||
foo = 42
|
foo = 42
|
||||||
|
|
||||||
@ -408,7 +425,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testColumnSelector() throws Exception {
|
public void testColumnSelector() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
## Specifies a selection of columns from the table on which an operation is
|
## Specifies a selection of columns from the table on which an operation is
|
||||||
going to be performed.
|
going to be performed.
|
||||||
type Column_Selector
|
type Column_Selector
|
||||||
@ -419,7 +437,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignments() throws Exception {
|
public void testAssignments() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from_java_set java_set =
|
from_java_set java_set =
|
||||||
owner = Vector.new_builder
|
owner = Vector.new_builder
|
||||||
group = Vector.new_builder
|
group = Vector.new_builder
|
||||||
@ -429,7 +448,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNumberTimes() throws Exception {
|
public void testNumberTimes() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
Standard.Base.Number.times : List Any
|
Standard.Base.Number.times : List Any
|
||||||
Standard.Base.Number.times self act =
|
Standard.Base.Number.times self act =
|
||||||
act
|
act
|
||||||
@ -438,7 +458,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIfThenBlock() throws Exception {
|
public void testIfThenBlock() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from_java_set java_set =
|
from_java_set java_set =
|
||||||
if java_set.contains PosixFilePermission.OWNER_READ then
|
if java_set.contains PosixFilePermission.OWNER_READ then
|
||||||
owner.append Read
|
owner.append Read
|
||||||
@ -449,7 +470,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvokeFilePermissions() throws Exception {
|
public void testInvokeFilePermissions() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from_java_set java_set =
|
from_java_set java_set =
|
||||||
File_Permissions owner.to_vector group.to_vector others.to_vector
|
File_Permissions owner.to_vector group.to_vector others.to_vector
|
||||||
""");
|
""");
|
||||||
@ -514,7 +536,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTextLiteralWithEscape() throws Exception {
|
public void testTextLiteralWithEscape() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
wrap_junit_testsuites = '<?xml version="1.0"\\tencoding="UTF-8"?>\\n'
|
wrap_junit_testsuites = '<?xml version="1.0"\\tencoding="UTF-8"?>\\n'
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
@ -546,7 +569,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiParameterFunction() throws Exception {
|
public void testMultiParameterFunction() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
import Standard.Base.System
|
import Standard.Base.System
|
||||||
|
|
||||||
@ -558,7 +582,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTestGroup() throws Exception {
|
public void testTestGroup() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Test
|
type Test
|
||||||
## Creates a new test group, describing properties of the object
|
## Creates a new test group, describing properties of the object
|
||||||
described by `self`.
|
described by `self`.
|
||||||
@ -582,7 +607,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyGroup() throws Exception {
|
public void testEmptyGroup() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
main =
|
main =
|
||||||
x = Panic.catch Any () .convert_to_dataflow_error
|
x = Panic.catch Any () .convert_to_dataflow_error
|
||||||
x.catch_primitive err->
|
x.catch_primitive err->
|
||||||
@ -602,7 +628,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTestGroupSimple() throws Exception {
|
public void testTestGroupSimple() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
group1 : Text -> Any -> (Text | Nothing) -> Nothing
|
group1 : Text -> Any -> (Text | Nothing) -> Nothing
|
||||||
|
|
||||||
type Test
|
type Test
|
||||||
@ -612,7 +639,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWildcardLeftHandSide() throws Exception {
|
public void testWildcardLeftHandSide() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
Any.should_succeed self frames_to_skip=0 =
|
Any.should_succeed self frames_to_skip=0 =
|
||||||
_ = frames_to_skip
|
_ = frames_to_skip
|
||||||
""");
|
""");
|
||||||
@ -628,7 +656,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReverseList() throws Exception {
|
public void testReverseList() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
reverse_list list =
|
reverse_list list =
|
||||||
go = list -> acc -> case list of
|
go = list -> acc -> case list of
|
||||||
List.Cons h t -> go t (List.Cons h acc)
|
List.Cons h t -> go t (List.Cons h acc)
|
||||||
@ -642,7 +671,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProblemHandling() throws Exception {
|
public void testProblemHandling() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
test_problem_handling : (Problem_Behavior -> Any) -> Vector Any -> (Any -> Nothing) -> Nothing
|
test_problem_handling : (Problem_Behavior -> Any) -> Vector Any -> (Any -> Nothing) -> Nothing
|
||||||
test_problem_handling action expected_problems result_checker =
|
test_problem_handling action expected_problems result_checker =
|
||||||
result_checker result_ignoring
|
result_checker result_ignoring
|
||||||
@ -651,7 +681,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProblemHandling2() throws Exception {
|
public void testProblemHandling2() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
test_problem_handling action expected_problems result_checker =
|
test_problem_handling action expected_problems result_checker =
|
||||||
error_result . should_fail_with first_problem_type frames_to_skip=3
|
error_result . should_fail_with first_problem_type frames_to_skip=3
|
||||||
warnings_checker warnings =
|
warnings_checker warnings =
|
||||||
@ -697,7 +728,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTableDataArgumentInCase() throws Exception {
|
public void testTableDataArgumentInCase() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
process_to_json_text value =
|
process_to_json_text value =
|
||||||
json = case value of
|
json = case value of
|
||||||
Table.Table_Data _ -> json_from_table value
|
Table.Table_Data _ -> json_from_table value
|
||||||
@ -707,7 +739,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVisualizationCaseOf() throws Exception {
|
public void testVisualizationCaseOf() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
prepare_visualization : Any -> Integer -> Json
|
prepare_visualization : Any -> Integer -> Json
|
||||||
prepare_visualization x max_rows=1000 = case x of
|
prepare_visualization x max_rows=1000 = case x of
|
||||||
Array ->
|
Array ->
|
||||||
@ -721,7 +754,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAggregateColumnGroupByTrue() throws Exception {
|
public void testAggregateColumnGroupByTrue() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
prepare_aggregate_columns : [Aggregate_Column] -> Table -> Problem_Behavior -> Resolved_Aggregate_Columns
|
prepare_aggregate_columns : [Aggregate_Column] -> Table -> Problem_Behavior -> Resolved_Aggregate_Columns
|
||||||
prepare_aggregate_columns aggregates table =
|
prepare_aggregate_columns aggregates table =
|
||||||
# Grouping Key
|
# Grouping Key
|
||||||
@ -762,7 +796,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTypeSignature() throws Exception {
|
public void testTypeSignature() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
resolve_aggregate table problem_builder aggregate_column =
|
resolve_aggregate table problem_builder aggregate_column =
|
||||||
table_columns = table.columns
|
table_columns = table.columns
|
||||||
|
|
||||||
@ -797,7 +832,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSelfTypeKeyword() throws Exception {
|
public void testSelfTypeKeyword() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type My_Type
|
type My_Type
|
||||||
Cons_A x
|
Cons_A x
|
||||||
Cons_B y=(Self.Cons_A 10)
|
Cons_B y=(Self.Cons_A 10)
|
||||||
@ -820,8 +856,6 @@ public class EnsoParserTest {
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseOnTextLiteral() throws Exception {
|
public void testCaseOnTextLiteral() throws Exception {
|
||||||
parseTest("""
|
parseTest("""
|
||||||
@ -874,7 +908,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testVectorVectorAny() throws Exception {
|
public void testVectorVectorAny() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Vector
|
type Vector
|
||||||
build : Standard.Base.Vector.Matrix Standard.Base.Any Standard.Base.Float
|
build : Standard.Base.Vector.Matrix Standard.Base.Any Standard.Base.Float
|
||||||
""");
|
""");
|
||||||
@ -890,7 +925,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOperatorSectionRight() throws Exception {
|
public void testOperatorSectionRight() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
type Filter_Condition
|
type Filter_Condition
|
||||||
to_predicate self = case self of
|
to_predicate self = case self of
|
||||||
Less value -> <value
|
Less value -> <value
|
||||||
@ -930,7 +966,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListBody() throws Exception {
|
public void testListBody() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
list directory name_filter=Nothing recursive=False =
|
list directory name_filter=Nothing recursive=False =
|
||||||
new directory . list name_filter=name_filter recursive=recursive
|
new directory . list name_filter=name_filter recursive=recursive
|
||||||
""");
|
""");
|
||||||
@ -947,7 +984,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseWithComment() throws Exception {
|
public void testCaseWithComment() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
ansi_bold : Boolean -> Text -> Text
|
ansi_bold : Boolean -> Text -> Text
|
||||||
ansi_bold enabled txt =
|
ansi_bold enabled txt =
|
||||||
case Platform.os of
|
case Platform.os of
|
||||||
@ -967,7 +1005,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGroupOfPatterns() throws Exception {
|
public void testGroupOfPatterns() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
sum self = case self of
|
sum self = case self of
|
||||||
Group (A _) (B _ _) (C _ e _) (D _ f _ g) -> e + f + g
|
Group (A _) (B _ _) (C _ e _) (D _ f _ g) -> e + f + g
|
||||||
""");
|
""");
|
||||||
@ -1034,7 +1073,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstructorMultipleNamedArgs1() throws Exception {
|
public void testConstructorMultipleNamedArgs1() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
x = Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive dot_matches_newline=True
|
x = Regex_Matcher.Regex_Matcher_Data case_sensitivity=Case_Sensitivity.Sensitive dot_matches_newline=True
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
@ -1064,7 +1104,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRuntimeServerTestCode() throws Exception {
|
public void testRuntimeServerTestCode() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from Standard.Base.Data.Numbers import Number
|
from Standard.Base.Data.Numbers import Number
|
||||||
|
|
||||||
main =
|
main =
|
||||||
@ -1077,7 +1118,10 @@ public class EnsoParserTest {
|
|||||||
y = self + 3
|
y = self + 3
|
||||||
z = y * x
|
z = y * x
|
||||||
z
|
z
|
||||||
""", true, true, true);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1098,7 +1142,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAtomBenchmarks1() throws Exception {
|
public void testAtomBenchmarks1() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
import Standard.Base.Data.List.List
|
import Standard.Base.Data.List.List
|
||||||
|
|
||||||
main =
|
main =
|
||||||
@ -1110,7 +1155,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAtomBenchmarks3() throws Exception {
|
public void testAtomBenchmarks3() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
import Standard.Base.Data.List.List
|
import Standard.Base.Data.List.List
|
||||||
|
|
||||||
List.mapReverse self f acc = case self of
|
List.mapReverse self f acc = case self of
|
||||||
@ -1120,12 +1166,16 @@ public class EnsoParserTest {
|
|||||||
main = list ->
|
main = list ->
|
||||||
res = list.mapReverse (x -> x + 1) List.Nil
|
res = list.mapReverse (x -> x + 1) List.Nil
|
||||||
res
|
res
|
||||||
""", true, true, false);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShouldQuoteValuesContainingTheCommentSymbol() throws Exception {
|
public void testShouldQuoteValuesContainingTheCommentSymbol() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
suite =
|
suite =
|
||||||
Test.specify "should quote values containing the comment symbol if comments are enabled" <|
|
Test.specify "should quote values containing the comment symbol if comments are enabled" <|
|
||||||
format = Delimited ',' . with_comments
|
format = Delimited ',' . with_comments
|
||||||
@ -1138,31 +1188,43 @@ public class EnsoParserTest {
|
|||||||
text_2 = File.read_text file
|
text_2 = File.read_text file
|
||||||
text_2.should_equal expected_text_2
|
text_2.should_equal expected_text_2
|
||||||
file.delete
|
file.delete
|
||||||
""", true, true, false);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyValueBetweenComments() throws Exception {
|
public void testEmptyValueBetweenComments() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
expected_text = normalize_lines <| \"""
|
expected_text = normalize_lines <| \"""
|
||||||
A,B
|
A,B
|
||||||
1,
|
1,
|
||||||
,""
|
,""
|
||||||
3,abc
|
3,abc
|
||||||
""", true, true, false);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuotedValues() throws Exception {
|
public void testQuotedValues() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
expected_text = normalize_lines <| \"""
|
expected_text = normalize_lines <| \"""
|
||||||
"one, two, three",-1.5,42,"4\"000",
|
"one, two, three",-1.5,42,"4\"000",
|
||||||
""", true, true, false);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleTripleQuote() throws Exception {
|
public void testSimpleTripleQuote() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
expected_response = Json.parse <| '''
|
expected_response = Json.parse <| '''
|
||||||
{
|
{
|
||||||
"headers": {
|
"headers": {
|
||||||
@ -1183,12 +1245,16 @@ public class EnsoParserTest {
|
|||||||
json = Json.parse <| '''
|
json = Json.parse <| '''
|
||||||
{"key":"val"}
|
{"key":"val"}
|
||||||
res = Http.new.post_json url_post json
|
res = Http.new.post_json url_post json
|
||||||
""", true, true, false);
|
""",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInThePresenceOfComments() throws Exception {
|
public void testInThePresenceOfComments() throws Exception {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
# this is a comment
|
# this is a comment
|
||||||
#this too
|
#this too
|
||||||
## But this is a doc.
|
## But this is a doc.
|
||||||
@ -1247,9 +1313,11 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockSyntax() throws Exception {
|
public void testBlockSyntax() throws Exception {
|
||||||
equivalenceTest("""
|
equivalenceTest(
|
||||||
|
"""
|
||||||
nums v fm ff n = v . map fm . filter ff . take n
|
nums v fm ff n = v . map fm . filter ff . take n
|
||||||
""", """
|
""",
|
||||||
|
"""
|
||||||
nums v fm ff n = v
|
nums v fm ff n = v
|
||||||
. map fm
|
. map fm
|
||||||
. filter ff
|
. filter ff
|
||||||
@ -1259,9 +1327,11 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockSyntaxOperators() throws Exception {
|
public void testBlockSyntaxOperators() throws Exception {
|
||||||
equivalenceTest("""
|
equivalenceTest(
|
||||||
|
"""
|
||||||
value = nums * each random + constant
|
value = nums * each random + constant
|
||||||
""", """
|
""",
|
||||||
|
"""
|
||||||
value = nums
|
value = nums
|
||||||
* each random
|
* each random
|
||||||
+ constant
|
+ constant
|
||||||
@ -1270,9 +1340,11 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockSyntaxOperators2() throws Exception {
|
public void testBlockSyntaxOperators2() throws Exception {
|
||||||
equivalenceTest("""
|
equivalenceTest(
|
||||||
|
"""
|
||||||
value = (nums + each random) * constant
|
value = (nums + each random) * constant
|
||||||
""", """
|
""",
|
||||||
|
"""
|
||||||
value = nums
|
value = nums
|
||||||
+ each random
|
+ each random
|
||||||
* constant
|
* constant
|
||||||
@ -1281,9 +1353,11 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockSyntaxOperators3() throws Exception {
|
public void testBlockSyntaxOperators3() throws Exception {
|
||||||
equivalenceTest("""
|
equivalenceTest(
|
||||||
|
"""
|
||||||
v = (rect1 . width) . center
|
v = (rect1 . width) . center
|
||||||
""", """
|
""",
|
||||||
|
"""
|
||||||
v = rect1
|
v = rect1
|
||||||
. width
|
. width
|
||||||
. center
|
. center
|
||||||
@ -1292,9 +1366,11 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBlockSyntaxOperators4() throws Exception {
|
public void testBlockSyntaxOperators4() throws Exception {
|
||||||
equivalenceTest("""
|
equivalenceTest(
|
||||||
|
"""
|
||||||
v = (rect1 . width 4) . center 3 2
|
v = (rect1 . width 4) . center 3 2
|
||||||
""", """
|
""",
|
||||||
|
"""
|
||||||
v = rect1
|
v = rect1
|
||||||
. width 4
|
. width 4
|
||||||
. center 3 2
|
. center 3 2
|
||||||
@ -1303,18 +1379,18 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrivateModules() throws Exception {
|
public void testPrivateModules() throws Exception {
|
||||||
List<String> moduleCodes = List.of(
|
List<String> moduleCodes =
|
||||||
"private",
|
List.of(
|
||||||
"""
|
"private",
|
||||||
|
"""
|
||||||
# Comment
|
# Comment
|
||||||
private
|
private
|
||||||
""",
|
""",
|
||||||
"""
|
"""
|
||||||
# Comment with empty line
|
# Comment with empty line
|
||||||
|
|
||||||
private
|
private
|
||||||
"""
|
""");
|
||||||
);
|
|
||||||
for (var moduleCode : moduleCodes) {
|
for (var moduleCode : moduleCodes) {
|
||||||
parseTest(moduleCode);
|
parseTest(moduleCode);
|
||||||
var module = compile("private");
|
var module = compile("private");
|
||||||
@ -1326,7 +1402,8 @@ public class EnsoParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ise_184219679() throws IOException {
|
public void ise_184219679() throws IOException {
|
||||||
parseTest("""
|
parseTest(
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
main =
|
main =
|
||||||
@ -1338,11 +1415,12 @@ public class EnsoParserTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void parseTest(String code) throws IOException {
|
private static void parseTest(String code) throws IOException {
|
||||||
parseTest(code, true, true, true);
|
parseTest(code, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static void parseTest(String code, boolean noIds, boolean noLocations, boolean lessDocs) throws IOException {
|
private static void parseTest(String code, boolean noIds, boolean noLocations, boolean lessDocs)
|
||||||
|
throws IOException {
|
||||||
var ir = compile(code);
|
var ir = compile(code);
|
||||||
assertNotNull(ir);
|
assertNotNull(ir);
|
||||||
}
|
}
|
||||||
@ -1373,8 +1451,18 @@ public class EnsoParserTest {
|
|||||||
var home = new File(System.getProperty("java.io.tmpdir")).toPath();
|
var home = new File(System.getProperty("java.io.tmpdir")).toPath();
|
||||||
var file1 = home.resolve(name + ".1");
|
var file1 = home.resolve(name + ".1");
|
||||||
var file2 = home.resolve(name + ".2");
|
var file2 = home.resolve(name + ".2");
|
||||||
Files.writeString(file1, ir1, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
Files.writeString(
|
||||||
Files.writeString(file2, ir2, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
|
file1,
|
||||||
|
ir1,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.WRITE);
|
||||||
|
Files.writeString(
|
||||||
|
file2,
|
||||||
|
ir2,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.WRITE);
|
||||||
assertEquals(msg, file1, file2);
|
assertEquals(msg, file1, file2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1388,18 +1476,17 @@ public class EnsoParserTest {
|
|||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Takes an {@link IR} and converts it to text representation suitable for
|
/**
|
||||||
* "diffing" while "simplifying" it.
|
* Takes an {@link IR} and converts it to text representation suitable for "diffing" while
|
||||||
|
* "simplifying" it.
|
||||||
*
|
*
|
||||||
* @param ir the intermediate representation
|
* @param ir the intermediate representation
|
||||||
* @param noIds remove all UUIDs or keep them? Multiple runs usually assign
|
* @param noIds remove all UUIDs or keep them? Multiple runs usually assign random/different UUIDs
|
||||||
* random/different UUIDs to various IR elements. Removing them is a best
|
* to various IR elements. Removing them is a best way to make the converted text comparable
|
||||||
* way to make the converted text comparable
|
* @param noLocations locations may slightly differ. Usually off-by-one. Especially when running
|
||||||
* @param noLocations locations may slightly differ. Usually off-by-one.
|
* old and new parser in parallel - removing them may be useful
|
||||||
* Especially when running old and new parser in parallel - removing them
|
* @param lessDocs documentation often isn't an essential part of the IR one can easily remove it
|
||||||
* may be useful
|
* by specifying {@code false}
|
||||||
* @param lessDocs documentation often isn't an essential part of the IR
|
|
||||||
* one can easily remove it by specifying {@code false}
|
|
||||||
* @return string representation of the IR
|
* @return string representation of the IR
|
||||||
*/
|
*/
|
||||||
private static String simplifyIR(IR ir, boolean noIds, boolean noLocations, boolean lessDocs) {
|
private static String simplifyIR(IR ir, boolean noIds, boolean noLocations, boolean lessDocs) {
|
||||||
@ -1408,10 +1495,13 @@ public class EnsoParserTest {
|
|||||||
}
|
}
|
||||||
String txt = ir.pretty();
|
String txt = ir.pretty();
|
||||||
if (noIds) {
|
if (noIds) {
|
||||||
txt = txt.replaceAll("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]", "_");
|
txt =
|
||||||
|
txt.replaceAll(
|
||||||
|
"[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]\\-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]",
|
||||||
|
"_");
|
||||||
}
|
}
|
||||||
if (lessDocs) {
|
if (lessDocs) {
|
||||||
for (;;) {
|
for (; ; ) {
|
||||||
final String pref = "Comment.Documentation(";
|
final String pref = "Comment.Documentation(";
|
||||||
int at = txt.indexOf(pref);
|
int at = txt.indexOf(pref);
|
||||||
if (at == -1) {
|
if (at == -1) {
|
||||||
@ -1420,7 +1510,7 @@ public class EnsoParserTest {
|
|||||||
int to = txt.indexOf("location =", at + pref.length());
|
int to = txt.indexOf("location =", at + pref.length());
|
||||||
txt = txt.substring(0, at) + "Comment.Doc(" + txt.substring(to);
|
txt = txt.substring(0, at) + "Comment.Doc(" + txt.substring(to);
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (; ; ) {
|
||||||
final String pref = "Case.Pattern.Doc(";
|
final String pref = "Case.Pattern.Doc(";
|
||||||
int at = txt.indexOf(pref);
|
int at = txt.indexOf(pref);
|
||||||
if (at == -1) {
|
if (at == -1) {
|
||||||
@ -1430,7 +1520,7 @@ public class EnsoParserTest {
|
|||||||
txt = txt.substring(0, at) + "Comment.CaseDoc(" + txt.substring(to);
|
txt = txt.substring(0, at) + "Comment.CaseDoc(" + txt.substring(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (; ; ) {
|
||||||
final String pref = "errors.Syntax(";
|
final String pref = "errors.Syntax(";
|
||||||
int at = txt.indexOf(pref);
|
int at = txt.indexOf(pref);
|
||||||
if (at == -1) {
|
if (at == -1) {
|
||||||
@ -1441,5 +1531,4 @@ public class EnsoParserTest {
|
|||||||
}
|
}
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import java.util.Objects;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.enso.compiler.core.ir.DiagnosticStorage;
|
import org.enso.compiler.core.ir.DiagnosticStorage;
|
||||||
import org.enso.compiler.core.ir.IdentifiedLocation;
|
import org.enso.compiler.core.ir.IdentifiedLocation;
|
||||||
import org.enso.compiler.core.ir.Location;
|
import org.enso.compiler.core.ir.Location;
|
||||||
@ -19,7 +18,6 @@ import org.enso.persist.Persistance;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
|
|
||||||
import scala.Option;
|
import scala.Option;
|
||||||
import scala.Tuple2;
|
import scala.Tuple2;
|
||||||
import scala.collection.immutable.List;
|
import scala.collection.immutable.List;
|
||||||
@ -72,13 +70,15 @@ public class IrPersistanceTest {
|
|||||||
public void scalaImmutableMapIsLazy() throws Exception {
|
public void scalaImmutableMapIsLazy() throws Exception {
|
||||||
var s1 = new LazySeq("Hello");
|
var s1 = new LazySeq("Hello");
|
||||||
var s2 = new LazySeq("World");
|
var s2 = new LazySeq("World");
|
||||||
var in = (scala.collection.immutable.Map) scala.collection.immutable.Map$.MODULE$.empty()
|
var in =
|
||||||
.$plus(new Tuple2("Hello", s1))
|
(scala.collection.immutable.Map)
|
||||||
.$plus(new Tuple2("World", s2));
|
scala.collection.immutable.Map$.MODULE$
|
||||||
|
.empty()
|
||||||
|
.$plus(new Tuple2("Hello", s1))
|
||||||
|
.$plus(new Tuple2("World", s2));
|
||||||
|
|
||||||
LazySeq.forbidden = true;
|
LazySeq.forbidden = true;
|
||||||
var out = (scala.collection.immutable.Map)
|
var out = (scala.collection.immutable.Map) serde(scala.collection.immutable.Map.class, in, 64);
|
||||||
serde(scala.collection.immutable.Map.class, in, 64);
|
|
||||||
|
|
||||||
assertEquals("Two pairs element", 2, out.size());
|
assertEquals("Two pairs element", 2, out.size());
|
||||||
assertEquals("Two keys", 2, out.keySet().size());
|
assertEquals("Two keys", 2, out.keySet().size());
|
||||||
@ -250,14 +250,16 @@ public class IrPersistanceTest {
|
|||||||
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
||||||
assertEquals("Remains five", 5, plain.get(Service.class).value());
|
assertEquals("Remains five", 5, plain.get(Service.class).value());
|
||||||
|
|
||||||
var multiOnRead = Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var multiOnRead =
|
||||||
|
Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
assertEquals("Multiplied on read", 15, multiOnRead.get(Service.class).value());
|
assertEquals("Multiplied on read", 15, multiOnRead.get(Service.class).value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeReplace() throws Exception {
|
public void writeReplace() throws Exception {
|
||||||
var in = new Service(5);
|
var in = new Service(5);
|
||||||
var arr = Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var arr =
|
||||||
|
Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
|
|
||||||
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
||||||
assertEquals("Multiplied on write", 15, plain.get(Service.class).value());
|
assertEquals("Multiplied on write", 15, plain.get(Service.class).value());
|
||||||
@ -271,14 +273,16 @@ public class IrPersistanceTest {
|
|||||||
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
||||||
assertEquals("Remains five", 5, plain.get(ServiceSupply.class).supply().value());
|
assertEquals("Remains five", 5, plain.get(ServiceSupply.class).supply().value());
|
||||||
|
|
||||||
var multiOnRead = Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var multiOnRead =
|
||||||
|
Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
assertEquals("Multiplied on read", 15, multiOnRead.get(ServiceSupply.class).supply().value());
|
assertEquals("Multiplied on read", 15, multiOnRead.get(ServiceSupply.class).supply().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeReplaceInline() throws Exception {
|
public void writeReplaceInline() throws Exception {
|
||||||
var in = new ServiceSupply(new Service(5));
|
var in = new ServiceSupply(new Service(5));
|
||||||
var arr = Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var arr =
|
||||||
|
Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
|
|
||||||
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
||||||
assertEquals("Multiplied on write", 15, plain.get(ServiceSupply.class).supply().value());
|
assertEquals("Multiplied on write", 15, plain.get(ServiceSupply.class).supply().value());
|
||||||
@ -293,14 +297,17 @@ public class IrPersistanceTest {
|
|||||||
assertEquals("Remains five", 5, (int) plain.get(IntegerSupply.class).supply().get());
|
assertEquals("Remains five", 5, (int) plain.get(IntegerSupply.class).supply().get());
|
||||||
assertEquals("Remains five 2", 5, (int) plain.get(IntegerSupply.class).supply().get());
|
assertEquals("Remains five 2", 5, (int) plain.get(IntegerSupply.class).supply().get());
|
||||||
|
|
||||||
var multiOnRead = Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var multiOnRead =
|
||||||
assertEquals("Multiplied on read", 15, (int) multiOnRead.get(IntegerSupply.class).supply().get());
|
Persistance.read(arr, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
|
assertEquals(
|
||||||
|
"Multiplied on read", 15, (int) multiOnRead.get(IntegerSupply.class).supply().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeReplaceReference() throws Exception {
|
public void writeReplaceReference() throws Exception {
|
||||||
var in = new IntegerSupply(new Service(5));
|
var in = new IntegerSupply(new Service(5));
|
||||||
var arr = Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
var arr =
|
||||||
|
Persistance.write(in, (obj) -> obj instanceof Service s ? new Service(s.value() * 3) : obj);
|
||||||
|
|
||||||
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
var plain = Persistance.read(arr, (Function<Object, Object>) null);
|
||||||
assertEquals("Multiplied on write", 15, (int) plain.get(IntegerSupply.class).supply().get());
|
assertEquals("Multiplied on write", 15, (int) plain.get(IntegerSupply.class).supply().get());
|
||||||
@ -414,7 +421,7 @@ public class IrPersistanceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Persistable(clazz=Service.class, id=432434)
|
@Persistable(clazz = Service.class, id = 432434)
|
||||||
public record Service(int value) implements Supplier<Integer> {
|
public record Service(int value) implements Supplier<Integer> {
|
||||||
@Override
|
@Override
|
||||||
public Integer get() {
|
public Integer get() {
|
||||||
@ -422,9 +429,9 @@ public class IrPersistanceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Persistable(clazz=IntegerSupply.class, id=432435)
|
@Persistable(clazz = IntegerSupply.class, id = 432435)
|
||||||
public record IntegerSupply(Supplier<Integer> supply) {}
|
public record IntegerSupply(Supplier<Integer> supply) {}
|
||||||
|
|
||||||
@Persistable(clazz=ServiceSupply.class, id=432436)
|
@Persistable(clazz = ServiceSupply.class, id = 432436)
|
||||||
public record ServiceSupply(Service supply) {}
|
public record ServiceSupply(Service supply) {}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import org.enso.interpreter.instrument.job.VisualizationResult;
|
import org.enso.interpreter.instrument.job.VisualizationResult;
|
||||||
import org.enso.polyglot.HostEnsoUtils;
|
import org.enso.polyglot.HostEnsoUtils;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.PolyglotException;
|
import org.graalvm.polyglot.PolyglotException;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -29,7 +29,8 @@ public class FindExceptionMessageTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThrowNPE() {
|
public void testThrowNPE() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
from Standard.Base import Panic
|
from Standard.Base import Panic
|
||||||
polyglot java import java.lang.NullPointerException
|
polyglot java import java.lang.NullPointerException
|
||||||
|
|
||||||
@ -48,7 +49,8 @@ public class FindExceptionMessageTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThrowNPEWithName() {
|
public void testThrowNPEWithName() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
from Standard.Base import Panic
|
from Standard.Base import Panic
|
||||||
polyglot java import java.lang.NullPointerException
|
polyglot java import java.lang.NullPointerException
|
||||||
|
|
||||||
@ -67,7 +69,8 @@ public class FindExceptionMessageTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPanic() {
|
public void testPanic() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
from Standard.Base import Panic
|
from Standard.Base import Panic
|
||||||
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
|
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
|
||||||
|
|
||||||
@ -87,12 +90,14 @@ public class FindExceptionMessageTest extends TestBase {
|
|||||||
var msg = HostEnsoUtils.findExceptionMessage(ex);
|
var msg = HostEnsoUtils.findExceptionMessage(ex);
|
||||||
assertEquals(exp, msg);
|
assertEquals(exp, msg);
|
||||||
|
|
||||||
executeInContext(ctx, () -> {
|
executeInContext(
|
||||||
var guestException = extractHostException(ex);
|
ctx,
|
||||||
var guestMsg = VisualizationResult.findExceptionMessage(guestException);
|
() -> {
|
||||||
assertEquals(exp, guestMsg);
|
var guestException = extractHostException(ex);
|
||||||
return null;
|
var guestMsg = VisualizationResult.findExceptionMessage(guestException);
|
||||||
});
|
assertEquals(exp, guestMsg);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Throwable extractHostException(PolyglotException ex) {
|
static Throwable extractHostException(PolyglotException ex) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.instrumentation.EventContext;
|
import com.oracle.truffle.api.instrumentation.EventContext;
|
||||||
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
|
import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
|
||||||
@ -9,10 +11,6 @@ import com.oracle.truffle.api.instrumentation.TruffleInstrument;
|
|||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.enso.interpreter.node.MethodRootNode;
|
|
||||||
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
|
|
||||||
import org.enso.pkg.QualifiedName;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -20,7 +18,9 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import static org.junit.Assert.fail;
|
import org.enso.interpreter.node.MethodRootNode;
|
||||||
|
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
|
||||||
|
import org.enso.pkg.QualifiedName;
|
||||||
|
|
||||||
/** Testing instrument to control newly created nodes. */
|
/** Testing instrument to control newly created nodes. */
|
||||||
@TruffleInstrument.Registration(
|
@TruffleInstrument.Registration(
|
||||||
@ -48,8 +48,8 @@ public class NodeCountingTestInstrument extends TruffleInstrument {
|
|||||||
|
|
||||||
public void enable(SourceSectionFilter filter) {
|
public void enable(SourceSectionFilter filter) {
|
||||||
this.env
|
this.env
|
||||||
.getInstrumenter()
|
.getInstrumenter()
|
||||||
.attachExecutionEventFactory(filter, new CountingAndFunctionCallFactory());
|
.attachExecutionEventFactory(filter, new CountingAndFunctionCallFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<UUID, FunctionCallInfo> registeredCalls() {
|
public Map<UUID, FunctionCallInfo> registeredCalls() {
|
||||||
@ -121,17 +121,17 @@ public class NodeCountingTestInstrument extends TruffleInstrument {
|
|||||||
public void onReturnValue(VirtualFrame frame, Object result) {
|
public void onReturnValue(VirtualFrame frame, Object result) {
|
||||||
Node node = context.getInstrumentedNode();
|
Node node = context.getInstrumentedNode();
|
||||||
if (node instanceof FunctionCallInstrumentationNode instrumentableNode
|
if (node instanceof FunctionCallInstrumentationNode instrumentableNode
|
||||||
&& result instanceof FunctionCallInstrumentationNode.FunctionCall functionCall) {
|
&& result instanceof FunctionCallInstrumentationNode.FunctionCall functionCall) {
|
||||||
onFunctionReturn(instrumentableNode, functionCall);
|
onFunctionReturn(instrumentableNode, functionCall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onFunctionReturn(FunctionCallInstrumentationNode node, FunctionCallInstrumentationNode.FunctionCall result) {
|
private void onFunctionReturn(
|
||||||
|
FunctionCallInstrumentationNode node, FunctionCallInstrumentationNode.FunctionCall result) {
|
||||||
if (node.getId() != null) {
|
if (node.getId() != null) {
|
||||||
calls.put(node.getId(), new FunctionCallInfo(result));
|
calls.put(node.getId(), new FunctionCallInfo(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FunctionCallInfo {
|
public static class FunctionCallInfo {
|
||||||
@ -163,8 +163,8 @@ public class NodeCountingTestInstrument extends TruffleInstrument {
|
|||||||
}
|
}
|
||||||
FunctionCallInfo that = (FunctionCallInfo) o;
|
FunctionCallInfo that = (FunctionCallInfo) o;
|
||||||
return Objects.equals(moduleName, that.moduleName)
|
return Objects.equals(moduleName, that.moduleName)
|
||||||
&& Objects.equals(typeName, that.typeName)
|
&& Objects.equals(typeName, that.typeName)
|
||||||
&& Objects.equals(functionName, that.functionName);
|
&& Objects.equals(functionName, that.functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package org.enso.interpreter.test.instrument;
|
package org.enso.interpreter.test.instrument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
|
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
|
||||||
import com.oracle.truffle.api.instrumentation.StandardTags;
|
import com.oracle.truffle.api.instrumentation.StandardTags;
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.enso.interpreter.node.ClosureRootNode;
|
import org.enso.interpreter.node.ClosureRootNode;
|
||||||
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
||||||
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
||||||
@ -20,10 +24,6 @@ import org.graalvm.polyglot.Source;
|
|||||||
import org.graalvm.polyglot.io.IOAccess;
|
import org.graalvm.polyglot.io.IOAccess;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -34,27 +34,28 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initContext() {
|
public void initContext() {
|
||||||
context = Context.newBuilder()
|
context =
|
||||||
.allowExperimentalOptions(true)
|
Context.newBuilder()
|
||||||
.option(
|
.allowExperimentalOptions(true)
|
||||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
.option(
|
||||||
Paths.get("../../distribution/component").toFile().getAbsolutePath()
|
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||||
)
|
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||||
.option(
|
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||||
RuntimeOptions.LOG_LEVEL,
|
.logHandler(System.err)
|
||||||
Level.WARNING.getName()
|
.allowExperimentalOptions(true)
|
||||||
)
|
.allowIO(IOAccess.ALL)
|
||||||
.logHandler(System.err)
|
.allowAllAccess(true)
|
||||||
.allowExperimentalOptions(true)
|
.build();
|
||||||
.allowIO(IOAccess.ALL)
|
|
||||||
.allowAllAccess(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var engine = context.getEngine();
|
var engine = context.getEngine();
|
||||||
Map<String, Language> langs = engine.getLanguages();
|
Map<String, Language> langs = engine.getLanguages();
|
||||||
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
|
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
|
||||||
|
|
||||||
nodes = engine.getInstruments().get(NodeCountingTestInstrument.INSTRUMENT_ID).lookup(NodeCountingTestInstrument.class);
|
nodes =
|
||||||
|
engine
|
||||||
|
.getInstruments()
|
||||||
|
.get(NodeCountingTestInstrument.INSTRUMENT_ID)
|
||||||
|
.lookup(NodeCountingTestInstrument.class);
|
||||||
nodes.enable();
|
nodes.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +66,8 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void avoidIdInstrumentationInLambdaMapFunctionWithFloor() throws Exception {
|
public void avoidIdInstrumentationInLambdaMapFunctionWithFloor() throws Exception {
|
||||||
var code = """
|
var code =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
import Standard.Visualization
|
import Standard.Visualization
|
||||||
|
|
||||||
@ -77,18 +79,21 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
var res = run.execute(10000);
|
var res = run.execute(10000);
|
||||||
assertEquals("Array of the requested size computed", 10000, res.getArraySize());
|
assertEquals("Array of the requested size computed", 10000, res.getArraySize());
|
||||||
|
|
||||||
Predicate<SourceSection> isLambda = (ss) -> {
|
Predicate<SourceSection> isLambda =
|
||||||
var sameSrc = ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
(ss) -> {
|
||||||
var st = ss.getCharacters().toString();
|
var sameSrc =
|
||||||
return sameSrc && st.contains("floor") && !st.contains("map");
|
ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
||||||
};
|
var st = ss.getCharacters().toString();
|
||||||
|
return sameSrc && st.contains("floor") && !st.contains("map");
|
||||||
|
};
|
||||||
|
|
||||||
assertAvoidIdInstrumentationTag(isLambda);
|
assertAvoidIdInstrumentationTag(isLambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void avoidIdInstrumentationInLambdaMapFunctionYear2010() throws Exception {
|
public void avoidIdInstrumentationInLambdaMapFunctionYear2010() throws Exception {
|
||||||
var code = """
|
var code =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
operator13 = [ 1973, 1975, 2005, 2006 ]
|
operator13 = [ 1973, 1975, 2005, 2006 ]
|
||||||
@ -104,18 +109,21 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
assertEquals("Size is 2", 2, element.getArraySize());
|
assertEquals("Size is 2", 2, element.getArraySize());
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate<SourceSection> isLambda = (ss) -> {
|
Predicate<SourceSection> isLambda =
|
||||||
var sameSrc = ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
(ss) -> {
|
||||||
var st = ss.getCharacters().toString();
|
var sameSrc =
|
||||||
return sameSrc && st.contains("2010") && !st.contains("map");
|
ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
||||||
};
|
var st = ss.getCharacters().toString();
|
||||||
|
return sameSrc && st.contains("2010") && !st.contains("map");
|
||||||
|
};
|
||||||
|
|
||||||
assertAvoidIdInstrumentationTag(isLambda);
|
assertAvoidIdInstrumentationTag(isLambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void avoidIdInstrumentationInMap() throws Exception {
|
public void avoidIdInstrumentationInMap() throws Exception {
|
||||||
var code = """
|
var code =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
run =
|
run =
|
||||||
@ -129,16 +137,17 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
var res = module.invokeMember("eval_expression", "run");
|
var res = module.invokeMember("eval_expression", "run");
|
||||||
assertEquals("Array of the requested size computed", 2, res.getArraySize());
|
assertEquals("Array of the requested size computed", 2, res.getArraySize());
|
||||||
|
|
||||||
Predicate<SourceSection> isLambda = (ss) -> {
|
Predicate<SourceSection> isLambda =
|
||||||
var sameSrc = ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
(ss) -> {
|
||||||
var st = ss.getCharacters().toString();
|
var sameSrc =
|
||||||
return sameSrc && st.contains("Case.Lower") && !st.contains("to_case");
|
ss.getSource().getCharacters().toString().equals(src.getCharacters().toString());
|
||||||
};
|
var st = ss.getCharacters().toString();
|
||||||
|
return sameSrc && st.contains("Case.Lower") && !st.contains("to_case");
|
||||||
|
};
|
||||||
|
|
||||||
assertAvoidIdInstrumentationTag(isLambda);
|
assertAvoidIdInstrumentationTag(isLambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertAvoidIdInstrumentationTag(Predicate<SourceSection> isLambda) {
|
private void assertAvoidIdInstrumentationTag(Predicate<SourceSection> isLambda) {
|
||||||
var found = nodes.assertNewNodes("Give me nodes", 0, 10000);
|
var found = nodes.assertNewNodes("Give me nodes", 0, 10000);
|
||||||
var err = new StringBuilder();
|
var err = new StringBuilder();
|
||||||
@ -151,7 +160,11 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isLambda.test(ss)) {
|
if (isLambda.test(ss)) {
|
||||||
err.append("\n").append("code: ").append(ss.getCharacters()).append(" for node ").append(n.getClass().getName());
|
err.append("\n")
|
||||||
|
.append("code: ")
|
||||||
|
.append(ss.getCharacters())
|
||||||
|
.append(" for node ")
|
||||||
|
.append(n.getClass().getName());
|
||||||
if (n instanceof InstrumentableNode in) {
|
if (n instanceof InstrumentableNode in) {
|
||||||
if (!hasAvoidIdInstrumentationTag(err, in, n.getRootNode())) {
|
if (!hasAvoidIdInstrumentationTag(err, in, n.getRootNode())) {
|
||||||
missingTagInLambda = true;
|
missingTagInLambda = true;
|
||||||
@ -168,7 +181,8 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
assertNotEquals("Found some nodes", 0, count);
|
assertNotEquals("Found some nodes", 0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAvoidIdInstrumentationTag(StringBuilder err, InstrumentableNode in, RootNode rn) {
|
private boolean hasAvoidIdInstrumentationTag(
|
||||||
|
StringBuilder err, InstrumentableNode in, RootNode rn) {
|
||||||
var hasAvoidIdInstrumentationTag = in.hasTag(AvoidIdInstrumentationTag.class);
|
var hasAvoidIdInstrumentationTag = in.hasTag(AvoidIdInstrumentationTag.class);
|
||||||
if (!hasAvoidIdInstrumentationTag) {
|
if (!hasAvoidIdInstrumentationTag) {
|
||||||
err.append("\nERROR!");
|
err.append("\nERROR!");
|
||||||
@ -176,10 +190,14 @@ public class AvoidIdInstrumentationTagTest {
|
|||||||
|
|
||||||
err.append("\n").append(" AvoidIdInstrumentationTag: ").append(hasAvoidIdInstrumentationTag);
|
err.append("\n").append(" AvoidIdInstrumentationTag: ").append(hasAvoidIdInstrumentationTag);
|
||||||
err.append("\n").append(" IdentifiedTag: ").append(in.hasTag(IdentifiedTag.class));
|
err.append("\n").append(" IdentifiedTag: ").append(in.hasTag(IdentifiedTag.class));
|
||||||
err.append("\n").append(" ExpressionTag: ").append(in.hasTag(StandardTags.ExpressionTag.class));
|
err.append("\n")
|
||||||
|
.append(" ExpressionTag: ")
|
||||||
|
.append(in.hasTag(StandardTags.ExpressionTag.class));
|
||||||
err.append("\n").append(" RootNode: ").append(rn);
|
err.append("\n").append(" RootNode: ").append(rn);
|
||||||
if (rn instanceof ClosureRootNode crn) {
|
if (rn instanceof ClosureRootNode crn) {
|
||||||
err.append("\n").append(" ClosureRootNode.subject to instr: ").append(crn.isSubjectToInstrumentation());
|
err.append("\n")
|
||||||
|
.append(" ClosureRootNode.subject to instr: ")
|
||||||
|
.append(crn.isSubjectToInstrumentation());
|
||||||
err.append("\n").append(" ClosureRootNode.used in bindings: ").append(crn.isUsedInBinding());
|
err.append("\n").append(" ClosureRootNode.used in bindings: ").append(crn.isUsedInBinding());
|
||||||
}
|
}
|
||||||
return hasAvoidIdInstrumentationTag;
|
return hasAvoidIdInstrumentationTag;
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package org.enso.interpreter.test.instrument;
|
package org.enso.interpreter.test.instrument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -20,20 +24,16 @@ import org.enso.polyglot.runtime.Runtime$Api$ExpressionUpdates;
|
|||||||
import org.enso.polyglot.runtime.Runtime$Api$InitializedNotification;
|
import org.enso.polyglot.runtime.Runtime$Api$InitializedNotification;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$MethodCall;
|
import org.enso.polyglot.runtime.Runtime$Api$MethodCall;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$MethodPointer;
|
import org.enso.polyglot.runtime.Runtime$Api$MethodPointer;
|
||||||
|
import org.enso.polyglot.runtime.Runtime$Api$OpenFileRequest;
|
||||||
|
import org.enso.polyglot.runtime.Runtime$Api$OpenFileResponse$;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$PushContextRequest;
|
import org.enso.polyglot.runtime.Runtime$Api$PushContextRequest;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$PushContextResponse;
|
import org.enso.polyglot.runtime.Runtime$Api$PushContextResponse;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$Request;
|
import org.enso.polyglot.runtime.Runtime$Api$Request;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$Response;
|
import org.enso.polyglot.runtime.Runtime$Api$Response;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$SetExpressionValueNotification;
|
import org.enso.polyglot.runtime.Runtime$Api$SetExpressionValueNotification;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$OpenFileRequest;
|
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$OpenFileResponse$;
|
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$StackItem$ExplicitCall;
|
import org.enso.polyglot.runtime.Runtime$Api$StackItem$ExplicitCall;
|
||||||
import org.enso.polyglot.runtime.Runtime$Api$StackItem$LocalCall;
|
import org.enso.polyglot.runtime.Runtime$Api$StackItem$LocalCall;
|
||||||
import org.enso.text.editing.model;
|
import org.enso.text.editing.model;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -72,7 +72,8 @@ public class IncrementalUpdatesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendUpdatesWhenFunctionBodyIsChanged() {
|
public void sendUpdatesWhenFunctionBodyIsChanged() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "5", "5", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
|
"4", ConstantsGen.INTEGER, "4", "5", "5", LiteralNode.class);
|
||||||
var m = context.languageContext().findModule(MODULE_NAME).orElse(null);
|
var m = context.languageContext().findModule(MODULE_NAME).orElse(null);
|
||||||
assertNotNull("Module found", m);
|
assertNotNull("Module found", m);
|
||||||
var numbers = m.getIr().preorder().filter((v1) -> v1 instanceof Literal.Number);
|
var numbers = m.getIr().preorder().filter((v1) -> v1 instanceof Literal.Number);
|
||||||
@ -84,17 +85,20 @@ public class IncrementalUpdatesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendUpdatesWhenWhenLineIsChangedBySettingValue() {
|
public void sendUpdatesWhenWhenLineIsChangedBySettingValue() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
|
"4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendUpdatesWhenWhenLineIsChangedByTextEdit() {
|
public void sendUpdatesWhenWhenLineIsChangedByTextEdit() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedByTextEdit("4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedByTextEdit(
|
||||||
|
"4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendMultipleUpdates() {
|
public void sendMultipleUpdates() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
|
"4", ConstantsGen.INTEGER, "4", "1000", "1000", LiteralNode.class);
|
||||||
sendExpressionValue("1000", "333");
|
sendExpressionValue("1000", "333");
|
||||||
assertEquals(List.newBuilder().addOne("333"), context.consumeOut());
|
assertEquals(List.newBuilder().addOne("333"), context.consumeOut());
|
||||||
nodeCountingInstrument.assertNewNodes("No execution on 333, no nodes yet", 0, 0);
|
nodeCountingInstrument.assertNewNodes("No execution on 333, no nodes yet", 0, 0);
|
||||||
@ -105,30 +109,38 @@ public class IncrementalUpdatesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendUpdatesWhenTextIsChangedByTextEdit() {
|
public void sendUpdatesWhenTextIsChangedByTextEdit() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedByTextEdit("\"hi\"", ConstantsGen.TEXT, "hi", "\"text\"", "text", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedByTextEdit(
|
||||||
|
"\"hi\"", ConstantsGen.TEXT, "hi", "\"text\"", "text", LiteralNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendUpdatesWhenTextIsChangedBySettingValue() {
|
public void sendUpdatesWhenTextIsChangedBySettingValue() {
|
||||||
sendUpdatesWhenFunctionBodyIsChangedBySettingValue("\"hi\"", ConstantsGen.TEXT, "hi", "\"text\"", "text", LiteralNode.class);
|
sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
|
"\"hi\"", ConstantsGen.TEXT, "hi", "\"text\"", "text", LiteralNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendNotANumberChange() {
|
public void sendNotANumberChange() {
|
||||||
var result = sendUpdatesWhenFunctionBodyIsChangedBySettingValue("4", ConstantsGen.INTEGER, "4", "x", null, LiteralNode.class);
|
var result =
|
||||||
assertTrue("Execution succeeds: " + result, result.head().payload() instanceof Runtime$Api$ExecutionComplete);
|
sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
assertEquals("Error is printed as a result",
|
"4", ConstantsGen.INTEGER, "4", "x", null, LiteralNode.class);
|
||||||
List.newBuilder().addOne("(Error: Uninitialized value)"), context.consumeOut()
|
assertTrue(
|
||||||
);
|
"Execution succeeds: " + result,
|
||||||
|
result.head().payload() instanceof Runtime$Api$ExecutionComplete);
|
||||||
|
assertEquals(
|
||||||
|
"Error is printed as a result",
|
||||||
|
List.newBuilder().addOne("(Error: Uninitialized value)"),
|
||||||
|
context.consumeOut());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String extractPositions(String code, String chars, Map<Character, int[]> beginAndLength) {
|
private static String extractPositions(
|
||||||
for (int at = 0; at < code.length();) {
|
String code, String chars, Map<Character, int[]> beginAndLength) {
|
||||||
|
for (int at = 0; at < code.length(); ) {
|
||||||
char ch = code.charAt(at);
|
char ch = code.charAt(at);
|
||||||
if (chars.indexOf(ch) >= 0) {
|
if (chars.indexOf(ch) >= 0) {
|
||||||
int[] prev = beginAndLength.get(ch);
|
int[] prev = beginAndLength.get(ch);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
beginAndLength.put(ch, new int[]{at, -1});
|
beginAndLength.put(ch, new int[] {at, -1});
|
||||||
} else if (prev[1] == -1) {
|
} else if (prev[1] == -1) {
|
||||||
prev[1] = at - prev[0];
|
prev[1] = at - prev[0];
|
||||||
} else {
|
} else {
|
||||||
@ -145,30 +157,55 @@ public class IncrementalUpdatesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChangedByTextEdit(
|
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChangedByTextEdit(
|
||||||
String originalText, String exprType, String originalOutput,
|
String originalText,
|
||||||
String newText, String executionOutput, Class<? extends Node> truffleNodeType
|
String exprType,
|
||||||
) {
|
String originalOutput,
|
||||||
return sendUpdatesWhenFunctionBodyIsChanged(originalText, exprType, originalOutput, newText, executionOutput, truffleNodeType, this::sendEditFile);
|
String newText,
|
||||||
|
String executionOutput,
|
||||||
|
Class<? extends Node> truffleNodeType) {
|
||||||
|
return sendUpdatesWhenFunctionBodyIsChanged(
|
||||||
|
originalText,
|
||||||
|
exprType,
|
||||||
|
originalOutput,
|
||||||
|
newText,
|
||||||
|
executionOutput,
|
||||||
|
truffleNodeType,
|
||||||
|
this::sendEditFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChangedBySettingValue(
|
||||||
String originalText, String exprType, String originalOutput,
|
String originalText,
|
||||||
String newText, String executionOutput, Class<? extends Node> truffleNodeType
|
String exprType,
|
||||||
) {
|
String originalOutput,
|
||||||
return sendUpdatesWhenFunctionBodyIsChanged(originalText, exprType, originalOutput, newText, executionOutput, truffleNodeType, this::sendExpressionValue);
|
String newText,
|
||||||
|
String executionOutput,
|
||||||
|
Class<? extends Node> truffleNodeType) {
|
||||||
|
return sendUpdatesWhenFunctionBodyIsChanged(
|
||||||
|
originalText,
|
||||||
|
exprType,
|
||||||
|
originalOutput,
|
||||||
|
newText,
|
||||||
|
executionOutput,
|
||||||
|
truffleNodeType,
|
||||||
|
this::sendExpressionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChanged(
|
private List<Runtime$Api$Response> sendUpdatesWhenFunctionBodyIsChanged(
|
||||||
String originalText, String exprType, String originalOutput,
|
String originalText,
|
||||||
String newText, String executionOutput, Class<? extends Node> truffleNodeType,
|
String exprType,
|
||||||
java.util.function.BiFunction<String, String, List<Runtime$Api$Response>> sendEdit
|
String originalOutput,
|
||||||
) {
|
String newText,
|
||||||
|
String executionOutput,
|
||||||
|
Class<? extends Node> truffleNodeType,
|
||||||
|
java.util.function.BiFunction<String, String, List<Runtime$Api$Response>> sendEdit) {
|
||||||
var contextId = UUID.randomUUID();
|
var contextId = UUID.randomUUID();
|
||||||
var requestId = UUID.randomUUID();
|
var requestId = UUID.randomUUID();
|
||||||
var metadata = new Metadata();
|
var metadata = new Metadata();
|
||||||
|
|
||||||
var pos = new HashMap<Character, int[]>();
|
var pos = new HashMap<Character, int[]>();
|
||||||
var code = extractPositions("""
|
var code =
|
||||||
|
extractPositions(
|
||||||
|
"""
|
||||||
import Standard.Base.IO
|
import Standard.Base.IO
|
||||||
|
|
||||||
&$foo$ =
|
&$foo$ =
|
||||||
@ -178,13 +215,16 @@ public class IncrementalUpdatesTest {
|
|||||||
main =
|
main =
|
||||||
y = @foo@
|
y = @foo@
|
||||||
%IO.println y%
|
%IO.println y%
|
||||||
""".replace("{originalText}", originalText),
|
"""
|
||||||
"&$#*@%", pos);
|
.replace("{originalText}", originalText),
|
||||||
|
"&$#*@%",
|
||||||
|
pos);
|
||||||
|
|
||||||
Function<Character, UUID> registerRegion = (ch) -> {
|
Function<Character, UUID> registerRegion =
|
||||||
int[] beginAndLength = pos.get(ch);
|
(ch) -> {
|
||||||
return metadata.addItem(beginAndLength[0], beginAndLength[1], null);
|
int[] beginAndLength = pos.get(ch);
|
||||||
};
|
return metadata.addItem(beginAndLength[0], beginAndLength[1], null);
|
||||||
|
};
|
||||||
// foo definition
|
// foo definition
|
||||||
registerRegion.apply('&');
|
registerRegion.apply('&');
|
||||||
// foo name
|
// foo name
|
||||||
@ -203,62 +243,61 @@ public class IncrementalUpdatesTest {
|
|||||||
var request = Request(requestId, new Runtime$Api$CreateContextRequest(contextId));
|
var request = Request(requestId, new Runtime$Api$CreateContextRequest(contextId));
|
||||||
context.send(request);
|
context.send(request);
|
||||||
var response = context.receive().get();
|
var response = context.receive().get();
|
||||||
assertEquals(response,
|
assertEquals(response, Response(requestId, new Runtime$Api$CreateContextResponse(contextId)));
|
||||||
Response(requestId, new Runtime$Api$CreateContextResponse(contextId))
|
|
||||||
);
|
|
||||||
// Open the new file
|
// Open the new file
|
||||||
context.send(
|
context.send(Request(requestId, new Runtime$Api$OpenFileRequest(mainFile, contents)));
|
||||||
Request(requestId, new Runtime$Api$OpenFileRequest(mainFile, contents))
|
|
||||||
);
|
|
||||||
response = context.receive().get();
|
response = context.receive().get();
|
||||||
assertEquals(response,
|
assertEquals(response, Response(requestId, Runtime$Api$OpenFileResponse$.MODULE$));
|
||||||
Response(requestId, Runtime$Api$OpenFileResponse$.MODULE$)
|
|
||||||
);
|
|
||||||
|
|
||||||
nodeCountingInstrument.assertNewNodes("No execution, no nodes yet", 0, 0);
|
nodeCountingInstrument.assertNewNodes("No execution, no nodes yet", 0, 0);
|
||||||
|
|
||||||
context.send(
|
context.send(
|
||||||
Request(
|
Request(
|
||||||
requestId,
|
requestId,
|
||||||
new Runtime$Api$PushContextRequest(
|
new Runtime$Api$PushContextRequest(
|
||||||
contextId,
|
contextId,
|
||||||
new Runtime$Api$StackItem$ExplicitCall(
|
new Runtime$Api$StackItem$ExplicitCall(
|
||||||
new Runtime$Api$MethodPointer(MODULE_NAME, "Enso_Test.Test.Main", "main"),
|
new Runtime$Api$MethodPointer(MODULE_NAME, "Enso_Test.Test.Main", "main"),
|
||||||
None(),
|
None(),
|
||||||
new Vector1<>(new String[]{"0"})
|
new Vector1<>(new String[] {"0"})))));
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertSameElements(context.receiveNIgnorePendingExpressionUpdates(4, 10, emptySet()),
|
assertSameElements(
|
||||||
Response(requestId, new Runtime$Api$PushContextResponse(contextId)),
|
context.receiveNIgnorePendingExpressionUpdates(4, 10, emptySet()),
|
||||||
TestMessages.update(contextId, mainFoo, exprType, new Runtime$Api$MethodCall(new Runtime$Api$MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo"), Vector$.MODULE$.empty())),
|
Response(requestId, new Runtime$Api$PushContextResponse(contextId)),
|
||||||
TestMessages.update(contextId, mainRes, ConstantsGen.NOTHING),
|
TestMessages.update(
|
||||||
context.executionComplete(contextId)
|
contextId,
|
||||||
);
|
mainFoo,
|
||||||
|
exprType,
|
||||||
|
new Runtime$Api$MethodCall(
|
||||||
|
new Runtime$Api$MethodPointer("Enso_Test.Test.Main", "Enso_Test.Test.Main", "foo"),
|
||||||
|
Vector$.MODULE$.empty())),
|
||||||
|
TestMessages.update(contextId, mainRes, ConstantsGen.NOTHING),
|
||||||
|
context.executionComplete(contextId));
|
||||||
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
|
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
|
||||||
|
|
||||||
var allNodesAfterException = nodeCountingInstrument.assertNewNodes("Execution creates some nodes", 20, 35);
|
var allNodesAfterException =
|
||||||
|
nodeCountingInstrument.assertNewNodes("Execution creates some nodes", 20, 35);
|
||||||
|
|
||||||
// push foo call
|
// push foo call
|
||||||
context.send(
|
context.send(
|
||||||
Request(
|
Request(
|
||||||
requestId,
|
requestId,
|
||||||
new Runtime$Api$PushContextRequest(contextId, new Runtime$Api$StackItem$LocalCall(mainFoo))
|
new Runtime$Api$PushContextRequest(
|
||||||
)
|
contextId, new Runtime$Api$StackItem$LocalCall(mainFoo))));
|
||||||
);
|
assertSameElements(
|
||||||
assertSameElements(context.receiveNIgnorePendingExpressionUpdates(4, 10, emptySet()),
|
context.receiveNIgnorePendingExpressionUpdates(4, 10, emptySet()),
|
||||||
Response(requestId, new Runtime$Api$PushContextResponse(contextId)),
|
Response(requestId, new Runtime$Api$PushContextResponse(contextId)),
|
||||||
TestMessages.update(contextId, fooX, exprType),
|
TestMessages.update(contextId, fooX, exprType),
|
||||||
TestMessages.update(contextId, fooRes, exprType),
|
TestMessages.update(contextId, fooRes, exprType),
|
||||||
context.executionComplete(contextId)
|
context.executionComplete(contextId));
|
||||||
);
|
|
||||||
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
|
assertEquals(List.newBuilder().addOne(originalOutput), context.consumeOut());
|
||||||
|
|
||||||
nodeCountingInstrument.assertNewNodes("No new nodes created", 0, 0);
|
nodeCountingInstrument.assertNewNodes("No new nodes created", 0, 0);
|
||||||
var literalNode = findLiteralNode(truffleNodeType, allNodesAfterException);
|
var literalNode = findLiteralNode(truffleNodeType, allNodesAfterException);
|
||||||
assertEquals("Check Literal node text in the source", originalText, literalNode.getSourceSection().getCharacters().toString());
|
assertEquals(
|
||||||
|
"Check Literal node text in the source",
|
||||||
|
originalText,
|
||||||
|
literalNode.getSourceSection().getCharacters().toString());
|
||||||
|
|
||||||
var executionCompleteEvents = sendEdit.apply(originalText, newText);
|
var executionCompleteEvents = sendEdit.apply(originalText, newText);
|
||||||
if (executionOutput != null) {
|
if (executionOutput != null) {
|
||||||
@ -266,50 +305,57 @@ public class IncrementalUpdatesTest {
|
|||||||
assertEquals(List.newBuilder().addOne(executionOutput), context.consumeOut());
|
assertEquals(List.newBuilder().addOne(executionOutput), context.consumeOut());
|
||||||
nodeCountingInstrument.assertNewNodes("No new nodes created", 0, 0);
|
nodeCountingInstrument.assertNewNodes("No new nodes created", 0, 0);
|
||||||
|
|
||||||
assertEquals("Literal node has been updated in the source", newText, literalNode.getSourceSection().getCharacters().toString());
|
assertEquals(
|
||||||
|
"Literal node has been updated in the source",
|
||||||
|
newText,
|
||||||
|
literalNode.getSourceSection().getCharacters().toString());
|
||||||
}
|
}
|
||||||
return executionCompleteEvents;
|
return executionCompleteEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runtime$Api$Response> sendEditFile(String originalText, String newText) {
|
private List<Runtime$Api$Response> sendEditFile(String originalText, String newText) {
|
||||||
assertNotNull("Main file must be defined before", mainFile);
|
assertNotNull("Main file must be defined before", mainFile);
|
||||||
context.send(Request(new Runtime$Api$EditFileNotification(
|
context.send(
|
||||||
mainFile,
|
Request(
|
||||||
makeSeq(
|
new Runtime$Api$EditFileNotification(
|
||||||
new model.TextEdit(
|
mainFile,
|
||||||
new model.Range(new model.Position(3, 8), new model.Position(3, 8 + originalText.length())),
|
makeSeq(
|
||||||
newText
|
new model.TextEdit(
|
||||||
)
|
new model.Range(
|
||||||
),
|
new model.Position(3, 8),
|
||||||
true
|
new model.Position(3, 8 + originalText.length())),
|
||||||
)));
|
newText)),
|
||||||
|
true)));
|
||||||
return context.receiveNIgnorePendingExpressionUpdates(1, 10, emptySet());
|
return context.receiveNIgnorePendingExpressionUpdates(1, 10, emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Runtime$Api$Response> sendExpressionValue(String originalText, String newText) {
|
private List<Runtime$Api$Response> sendExpressionValue(String originalText, String newText) {
|
||||||
assertNotNull("Main file must be defined before", mainFile);
|
assertNotNull("Main file must be defined before", mainFile);
|
||||||
context.send(Request(new Runtime$Api$SetExpressionValueNotification(
|
context.send(
|
||||||
mainFile,
|
Request(
|
||||||
makeSeq(
|
new Runtime$Api$SetExpressionValueNotification(
|
||||||
new model.TextEdit(
|
mainFile,
|
||||||
new model.Range(new model.Position(3, 8), new model.Position(3, 8 + originalText.length())),
|
makeSeq(
|
||||||
newText
|
new model.TextEdit(
|
||||||
)
|
new model.Range(
|
||||||
),
|
new model.Position(3, 8),
|
||||||
UUID.randomUUID(),
|
new model.Position(3, 8 + originalText.length())),
|
||||||
newText
|
newText)),
|
||||||
)));
|
UUID.randomUUID(),
|
||||||
|
newText)));
|
||||||
return context.receiveNIgnoreExpressionUpdates(1, 10);
|
return context.receiveNIgnoreExpressionUpdates(1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Node> T findLiteralNode(Class<T> type, Map<Class, java.util.List<Node>> nodes) {
|
private <T extends Node> T findLiteralNode(
|
||||||
|
Class<T> type, Map<Class, java.util.List<Node>> nodes) {
|
||||||
var intNodes = nodes.get(type);
|
var intNodes = nodes.get(type);
|
||||||
assertNotNull("Found LiteralNode in " + nodes, intNodes);
|
assertNotNull("Found LiteralNode in " + nodes, intNodes);
|
||||||
assertEquals("Expecting one node: " + intNodes, 1, intNodes.size());
|
assertEquals("Expecting one node: " + intNodes, 1, intNodes.size());
|
||||||
return type.cast(intNodes.get(0));
|
return type.cast(intNodes.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertSameElements(List<Runtime$Api$Response> actual, Runtime$Api$Response... seq) {
|
private static void assertSameElements(
|
||||||
|
List<Runtime$Api$Response> actual, Runtime$Api$Response... seq) {
|
||||||
assertEquals("Same size: " + actual, seq.length, actual.size());
|
assertEquals("Same size: " + actual, seq.length, actual.size());
|
||||||
for (int i = 0; i < seq.length; i++) {
|
for (int i = 0; i < seq.length; i++) {
|
||||||
var real = actual.drop(i).head();
|
var real = actual.drop(i).head();
|
||||||
@ -340,7 +386,8 @@ public class IncrementalUpdatesTest {
|
|||||||
return Set$.MODULE$.empty();
|
return Set$.MODULE$.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Runtime$Api$Request Request(UUID id, org.enso.polyglot.runtime.Runtime.ApiRequest request) {
|
private static Runtime$Api$Request Request(
|
||||||
|
UUID id, org.enso.polyglot.runtime.Runtime.ApiRequest request) {
|
||||||
return org.enso.polyglot.runtime.Runtime$Api$Request$.MODULE$.apply(id, request);
|
return org.enso.polyglot.runtime.Runtime$Api$Request$.MODULE$.apply(id, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,11 +395,13 @@ public class IncrementalUpdatesTest {
|
|||||||
return org.enso.polyglot.runtime.Runtime$Api$Request$.MODULE$.apply(request);
|
return org.enso.polyglot.runtime.Runtime$Api$Request$.MODULE$.apply(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Runtime$Api$Response Response(org.enso.polyglot.runtime.Runtime.ApiResponse request) {
|
private static Runtime$Api$Response Response(
|
||||||
|
org.enso.polyglot.runtime.Runtime.ApiResponse request) {
|
||||||
return org.enso.polyglot.runtime.Runtime$Api$Response$.MODULE$.apply(request);
|
return org.enso.polyglot.runtime.Runtime$Api$Response$.MODULE$.apply(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Runtime$Api$Response Response(UUID id, org.enso.polyglot.runtime.Runtime.ApiResponse request) {
|
private static Runtime$Api$Response Response(
|
||||||
|
UUID id, org.enso.polyglot.runtime.Runtime.ApiResponse request) {
|
||||||
return org.enso.polyglot.runtime.Runtime$Api$Response$.MODULE$.apply(id, request);
|
return org.enso.polyglot.runtime.Runtime$Api$Response$.MODULE$.apply(id, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
package org.enso.interpreter.test.instrument;
|
package org.enso.interpreter.test.instrument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
|
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
|
||||||
import com.oracle.truffle.api.instrumentation.StandardTags;
|
import com.oracle.truffle.api.instrumentation.StandardTags;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
||||||
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
||||||
import org.enso.interpreter.test.Metadata;
|
import org.enso.interpreter.test.Metadata;
|
||||||
@ -10,90 +15,86 @@ import org.enso.polyglot.RuntimeOptions;
|
|||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Language;
|
import org.graalvm.polyglot.Language;
|
||||||
import org.graalvm.polyglot.Source;
|
import org.graalvm.polyglot.Source;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
import org.graalvm.polyglot.io.IOAccess;
|
import org.graalvm.polyglot.io.IOAccess;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class WarningInstrumentationTest {
|
public class WarningInstrumentationTest {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private NodeCountingTestInstrument instrument;
|
private NodeCountingTestInstrument instrument;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initContext() {
|
public void initContext() {
|
||||||
context = Context.newBuilder()
|
context =
|
||||||
.allowExperimentalOptions(true)
|
Context.newBuilder()
|
||||||
.option(
|
.allowExperimentalOptions(true)
|
||||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
.option(
|
||||||
Paths.get("../../distribution/component").toFile().getAbsolutePath()
|
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||||
)
|
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||||
.option(
|
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||||
RuntimeOptions.LOG_LEVEL,
|
.logHandler(System.err)
|
||||||
Level.WARNING.getName()
|
.allowExperimentalOptions(true)
|
||||||
)
|
.allowIO(IOAccess.ALL)
|
||||||
.logHandler(System.err)
|
.allowAllAccess(true)
|
||||||
.allowExperimentalOptions(true)
|
.build();
|
||||||
.allowIO(IOAccess.ALL)
|
|
||||||
.allowAllAccess(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var engine = context.getEngine();
|
var engine = context.getEngine();
|
||||||
Map<String, Language> langs = engine.getLanguages();
|
Map<String, Language> langs = engine.getLanguages();
|
||||||
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
|
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
|
||||||
|
|
||||||
instrument = engine.getInstruments().get(NodeCountingTestInstrument.INSTRUMENT_ID).lookup(NodeCountingTestInstrument.class);
|
instrument =
|
||||||
SourceSectionFilter builder = SourceSectionFilter.newBuilder()
|
engine
|
||||||
.tagIs(StandardTags.ExpressionTag.class, StandardTags.CallTag.class)
|
.getInstruments()
|
||||||
.tagIs(IdentifiedTag.class)
|
.get(NodeCountingTestInstrument.INSTRUMENT_ID)
|
||||||
.tagIsNot(AvoidIdInstrumentationTag.class)
|
.lookup(NodeCountingTestInstrument.class);
|
||||||
.build();
|
SourceSectionFilter builder =
|
||||||
instrument.enable(builder);
|
SourceSectionFilter.newBuilder()
|
||||||
}
|
.tagIs(StandardTags.ExpressionTag.class, StandardTags.CallTag.class)
|
||||||
|
.tagIs(IdentifiedTag.class)
|
||||||
|
.tagIsNot(AvoidIdInstrumentationTag.class)
|
||||||
|
.build();
|
||||||
|
instrument.enable(builder);
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void disposeContext() {
|
public void disposeContext() {
|
||||||
context.close();
|
context.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void instrumentValueWithWarnings() throws Exception {
|
public void instrumentValueWithWarnings() throws Exception {
|
||||||
var metadata = new Metadata();
|
var metadata = new Metadata();
|
||||||
|
|
||||||
var idOp1 = metadata.addItem(151, 34, null);
|
var idOp1 = metadata.addItem(151, 34, null);
|
||||||
var idOp2 = metadata.addItem(202, 31, null);
|
var idOp2 = metadata.addItem(202, 31, null);
|
||||||
var idOp3 = metadata.addItem(250, 13, null);
|
var idOp3 = metadata.addItem(250, 13, null);
|
||||||
var rawCode = """
|
var rawCode =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
from Standard.Base.Warning import Warning
|
from Standard.Base.Warning import Warning
|
||||||
from Standard.Table.Data.Table import Table
|
from Standard.Table.Data.Table import Table
|
||||||
|
|
||||||
run column_name =
|
run column_name =
|
||||||
operator1 = Table.new [[column_name, [1,2,3]]]
|
operator1 = Table.new [[column_name, [1,2,3]]]
|
||||||
operator2 = Warning.attach "Text" operator1
|
operator2 = Warning.attach "Text" operator1
|
||||||
operator3 = operator2.get
|
operator3 = operator2.get
|
||||||
operator3
|
operator3
|
||||||
""";
|
""";
|
||||||
var code = metadata.appendToCode(rawCode);
|
var code = metadata.appendToCode(rawCode);
|
||||||
var src = Source.newBuilder("enso", code, "TestWarning.enso").build();
|
var src = Source.newBuilder("enso", code, "TestWarning.enso").build();
|
||||||
var module = context.eval(src);
|
var module = context.eval(src);
|
||||||
var res = module.invokeMember("eval_expression", "run");
|
var res = module.invokeMember("eval_expression", "run");
|
||||||
res.execute("A");
|
res.execute("A");
|
||||||
|
|
||||||
var calls = instrument.registeredCalls();
|
var calls = instrument.registeredCalls();
|
||||||
|
|
||||||
assertEquals(calls.keySet().size(), 3);
|
assertEquals(calls.keySet().size(), 3);
|
||||||
assertEquals(calls.get(idOp1).getFunctionName(), "new");
|
assertEquals(calls.get(idOp1).getFunctionName(), "new");
|
||||||
assertEquals(calls.get(idOp2).getFunctionName(), "attach");
|
assertEquals(calls.get(idOp2).getFunctionName(), "attach");
|
||||||
assertEquals(calls.get(idOp3).getTypeName().item(), "Table");
|
assertEquals(calls.get(idOp3).getTypeName().item(), "Table");
|
||||||
assertEquals(calls.get(idOp3).getFunctionName(), "get");
|
assertEquals(calls.get(idOp3).getFunctionName(), "get");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
@ -9,12 +14,6 @@ import org.junit.Before;
|
|||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
public class ConversionMethodTests extends TestBase {
|
public class ConversionMethodTests extends TestBase {
|
||||||
private static Context ctx;
|
private static Context ctx;
|
||||||
|
|
||||||
@ -41,17 +40,18 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleConversion() {
|
public void testSimpleConversion() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo foo
|
Mk_Foo foo
|
||||||
type Bar
|
type Bar
|
||||||
Mk_Bar bar
|
Mk_Bar bar
|
||||||
type Baz
|
type Baz
|
||||||
Mk_Baz baz
|
Mk_Baz baz
|
||||||
|
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.bar
|
Foo.from (that:Bar) = Foo.Mk_Foo that.bar
|
||||||
Foo.from (that:Baz) = Foo.Mk_Foo that.baz
|
Foo.from (that:Baz) = Foo.Mk_Foo that.baz
|
||||||
|
|
||||||
main = (Foo.from (Baz.Mk_Baz 10)).foo + (Foo.from (Bar.Mk_Bar 20)).foo
|
main = (Foo.from (Baz.Mk_Baz 10)).foo + (Foo.from (Bar.Mk_Bar 20)).foo
|
||||||
""";
|
""";
|
||||||
Value res = evalModule(ctx, src);
|
Value res = evalModule(ctx, src);
|
||||||
@ -60,15 +60,16 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchOnHostMap() {
|
public void testDispatchOnHostMap() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
polyglot java import java.util.Map as Java_Map
|
polyglot java import java.util.Map as Java_Map
|
||||||
import Standard.Base.Data.Map.Map
|
import Standard.Base.Data.Map.Map
|
||||||
|
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
|
|
||||||
Foo.from (that:Map) = Foo.Mk_Foo that
|
Foo.from (that:Map) = Foo.Mk_Foo that
|
||||||
|
|
||||||
main =
|
main =
|
||||||
jmap = Java_Map.of "A" 1 "B" 2 "C" 3
|
jmap = Java_Map.of "A" 1 "B" 2 "C" 3
|
||||||
Foo.from jmap . data . size
|
Foo.from jmap . data . size
|
||||||
@ -79,20 +80,21 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchOnJSMap() {
|
public void testDispatchOnJSMap() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
import Standard.Base.Data.Map.Map
|
import Standard.Base.Data.Map.Map
|
||||||
|
|
||||||
foreign js js_map = '''
|
foreign js js_map = '''
|
||||||
let m = new Map()
|
let m = new Map()
|
||||||
m.set("A", 1)
|
m.set("A", 1)
|
||||||
m.set("B", 2)
|
m.set("B", 2)
|
||||||
return m
|
return m
|
||||||
|
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
|
|
||||||
Foo.from (that:Map) = Foo.Mk_Foo that
|
Foo.from (that:Map) = Foo.Mk_Foo that
|
||||||
|
|
||||||
main =
|
main =
|
||||||
Foo.from js_map . data . size
|
Foo.from js_map . data . size
|
||||||
""";
|
""";
|
||||||
@ -102,17 +104,18 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchOnJSDateTime() {
|
public void testDispatchOnJSDateTime() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
import Standard.Base.Data.Time.Date_Time.Date_Time
|
import Standard.Base.Data.Time.Date_Time.Date_Time
|
||||||
|
|
||||||
foreign js js_date year month day hour minute second nanosecond = '''
|
foreign js js_date year month day hour minute second nanosecond = '''
|
||||||
return new Date(year, month - 1, day, hour, minute, second, nanosecond / 1000000);
|
return new Date(year, month - 1, day, hour, minute, second, nanosecond / 1000000);
|
||||||
|
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
|
|
||||||
Foo.from (that:Date_Time) = Foo.Mk_Foo that
|
Foo.from (that:Date_Time) = Foo.Mk_Foo that
|
||||||
|
|
||||||
main =
|
main =
|
||||||
Foo.from (js_date 2023 2 7 23 59 0 10) . data . day
|
Foo.from (js_date 2023 2 7 23 59 0 10) . data . day
|
||||||
""";
|
""";
|
||||||
@ -122,15 +125,16 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAmbiguousConversionStrictUnused() {
|
public void testAmbiguousConversionStrictUnused() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
type Bar
|
type Bar
|
||||||
Mk_Bar x
|
Mk_Bar x
|
||||||
|
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
||||||
|
|
||||||
main = 42
|
main = 42
|
||||||
""";
|
""";
|
||||||
try {
|
try {
|
||||||
@ -138,7 +142,11 @@ public class ConversionMethodTests extends TestBase {
|
|||||||
fail("Expected an exception, but got " + res);
|
fail("Expected an exception, but got " + res);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertEquals("Compilation aborted due to errors.", e.getMessage());
|
assertEquals("Compilation aborted due to errors.", e.getMessage());
|
||||||
MatcherAssert.assertThat(getStdOut(), Matchers.containsString("Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in this module."));
|
MatcherAssert.assertThat(
|
||||||
|
getStdOut(),
|
||||||
|
Matchers.containsString(
|
||||||
|
"Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in"
|
||||||
|
+ " this module."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
import java.util.concurrent.Executors;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -28,7 +28,8 @@ public class ForeignMethodInvokeTest extends TestBase {
|
|||||||
public void testForeignFunctionParseFailure() {
|
public void testForeignFunctionParseFailure() {
|
||||||
// python is not a permitted language, therefore, invoking `py_array` method
|
// python is not a permitted language, therefore, invoking `py_array` method
|
||||||
// should fail with a Polyglot_Error, rather than crashing whole engine.
|
// should fail with a Polyglot_Error, rather than crashing whole engine.
|
||||||
String source = """
|
String source =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
foreign python py_array = \"\"\"
|
foreign python py_array = \"\"\"
|
||||||
@ -36,21 +37,25 @@ public class ForeignMethodInvokeTest extends TestBase {
|
|||||||
|
|
||||||
main =
|
main =
|
||||||
Panic.recover Any py_array
|
Panic.recover Any py_array
|
||||||
""".trim();
|
"""
|
||||||
|
.trim();
|
||||||
Value module = ctx.eval("enso", source);
|
Value module = ctx.eval("enso", source);
|
||||||
Value res = module.invokeMember("eval_expression", "main");
|
Value res = module.invokeMember("eval_expression", "main");
|
||||||
assertTrue("Invoking non-installed foreign function should recover", res.isException());
|
assertTrue("Invoking non-installed foreign function should recover", res.isException());
|
||||||
try {
|
try {
|
||||||
throw res.throwException();
|
throw res.throwException();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertTrue("Wrong error message",
|
assertTrue(
|
||||||
e.getMessage().matches("Cannot parse foreign python method. Only available languages are .+"));
|
"Wrong error message",
|
||||||
|
e.getMessage()
|
||||||
|
.matches("Cannot parse foreign python method. Only available languages are .+"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInteropWithJavaScript() throws Exception {
|
public void testInteropWithJavaScript() throws Exception {
|
||||||
var source = """
|
var source =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
foreign js js_array t = \"\"\"
|
foreign js js_array t = \"\"\"
|
||||||
@ -68,9 +73,13 @@ public class ForeignMethodInvokeTest extends TestBase {
|
|||||||
assertEquals(2, res.getArrayElement(1).asInt());
|
assertEquals(2, res.getArrayElement(1).asInt());
|
||||||
assertEquals(13, res.getArrayElement(2).asInt());
|
assertEquals(13, res.getArrayElement(2).asInt());
|
||||||
|
|
||||||
var res2 = Executors.newSingleThreadExecutor().submit(() -> {
|
var res2 =
|
||||||
return third.execute(12);
|
Executors.newSingleThreadExecutor()
|
||||||
}).get();
|
.submit(
|
||||||
|
() -> {
|
||||||
|
return third.execute(12);
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
assertTrue("It is an array2", res2.hasArrayElements());
|
assertTrue("It is an array2", res2.hasArrayElements());
|
||||||
assertEquals(12, res2.getArrayElement(2).asInt());
|
assertEquals(12, res2.getArrayElement(2).asInt());
|
||||||
@ -79,7 +88,8 @@ public class ForeignMethodInvokeTest extends TestBase {
|
|||||||
@Ignore
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
public void testParallelInteropWithJavaScript() throws Exception {
|
public void testParallelInteropWithJavaScript() throws Exception {
|
||||||
var source = """
|
var source =
|
||||||
|
"""
|
||||||
from Standard.Base import all
|
from Standard.Base import all
|
||||||
|
|
||||||
polyglot java import java.lang.Thread
|
polyglot java import java.lang.Thread
|
||||||
@ -94,9 +104,12 @@ public class ForeignMethodInvokeTest extends TestBase {
|
|||||||
var module = ctx.eval("enso", source);
|
var module = ctx.eval("enso", source);
|
||||||
var third = module.invokeMember("eval_expression", "third");
|
var third = module.invokeMember("eval_expression", "third");
|
||||||
|
|
||||||
var future = Executors.newSingleThreadExecutor().submit(() -> {
|
var future =
|
||||||
return third.execute(12);
|
Executors.newSingleThreadExecutor()
|
||||||
});
|
.submit(
|
||||||
|
() -> {
|
||||||
|
return third.execute(12);
|
||||||
|
});
|
||||||
var res = third.execute(13);
|
var res = third.execute(13);
|
||||||
assertTrue("It is an array", res.hasArrayElements());
|
assertTrue("It is an array", res.hasArrayElements());
|
||||||
assertEquals(3, res.getArraySize());
|
assertEquals(3, res.getArraySize());
|
||||||
|
@ -1,57 +1,58 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.enso.polyglot.RuntimeOptions;
|
import org.enso.polyglot.RuntimeOptions;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Language;
|
import org.graalvm.polyglot.Language;
|
||||||
import org.graalvm.polyglot.Source;
|
import org.graalvm.polyglot.Source;
|
||||||
import org.graalvm.polyglot.io.IOAccess;
|
import org.graalvm.polyglot.io.IOAccess;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class InsightForEnsoTest {
|
public class InsightForEnsoTest {
|
||||||
private Context ctx;
|
private Context ctx;
|
||||||
private AutoCloseable insightHandle;
|
private AutoCloseable insightHandle;
|
||||||
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initContext() throws Exception {
|
public void initContext() throws Exception {
|
||||||
this.ctx = Context.newBuilder()
|
this.ctx =
|
||||||
.allowExperimentalOptions(true)
|
Context.newBuilder()
|
||||||
.option(
|
.allowExperimentalOptions(true)
|
||||||
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
.option(
|
||||||
Paths.get("../../distribution/component").toFile().getAbsolutePath()
|
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
|
||||||
)
|
Paths.get("../../distribution/component").toFile().getAbsolutePath())
|
||||||
.option(
|
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
|
||||||
RuntimeOptions.LOG_LEVEL,
|
.logHandler(System.err)
|
||||||
Level.WARNING.getName()
|
.allowExperimentalOptions(true)
|
||||||
)
|
.allowIO(IOAccess.ALL)
|
||||||
.logHandler(System.err)
|
.out(out)
|
||||||
.allowExperimentalOptions(true)
|
.allowAllAccess(true)
|
||||||
.allowIO(IOAccess.ALL)
|
.build();
|
||||||
.out(out)
|
|
||||||
.allowAllAccess(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var engine = ctx.getEngine();
|
var engine = ctx.getEngine();
|
||||||
Map<String, Language> langs = engine.getLanguages();
|
Map<String, Language> langs = engine.getLanguages();
|
||||||
assertNotNull("Enso found: " + langs, langs.get("enso"));
|
assertNotNull("Enso found: " + langs, langs.get("enso"));
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
var fn = (Function<Source,AutoCloseable>) engine.getInstruments().get("insight").lookup(Function.class);
|
var fn =
|
||||||
assertNotNull(fn);
|
(Function<Source, AutoCloseable>)
|
||||||
|
engine.getInstruments().get("insight").lookup(Function.class);
|
||||||
|
assertNotNull(fn);
|
||||||
|
|
||||||
var insightScript = Source.newBuilder("js", """
|
var insightScript =
|
||||||
|
Source.newBuilder(
|
||||||
|
"js",
|
||||||
|
"""
|
||||||
insight.on('enter', (ctx, frame) => {
|
insight.on('enter', (ctx, frame) => {
|
||||||
print(`${ctx.name} at ${ctx.source.name}:${ctx.line}:`);
|
print(`${ctx.name} at ${ctx.source.name}:${ctx.line}:`);
|
||||||
let dump = "";
|
let dump = "";
|
||||||
@ -63,40 +64,47 @@ public class InsightForEnsoTest {
|
|||||||
}, {
|
}, {
|
||||||
roots : true
|
roots : true
|
||||||
});
|
});
|
||||||
""", "trace.js").build();
|
""",
|
||||||
this.insightHandle = fn.apply(insightScript);
|
"trace.js")
|
||||||
}
|
.build();
|
||||||
|
this.insightHandle = fn.apply(insightScript);
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void disposeContext() throws Exception {
|
public void disposeContext() throws Exception {
|
||||||
this.insightHandle.close();
|
this.insightHandle.close();
|
||||||
this.ctx.close();
|
this.ctx.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void computeFactorial() throws Exception {
|
public void computeFactorial() throws Exception {
|
||||||
var code = Source.newBuilder("enso", """
|
var code =
|
||||||
|
Source.newBuilder(
|
||||||
|
"enso",
|
||||||
|
"""
|
||||||
fac n =
|
fac n =
|
||||||
acc n v = if n <= 1 then v else
|
acc n v = if n <= 1 then v else
|
||||||
@Tail_Call acc n-1 n*v
|
@Tail_Call acc n-1 n*v
|
||||||
|
|
||||||
acc n 1
|
acc n 1
|
||||||
""", "factorial.enso").build();
|
""",
|
||||||
|
"factorial.enso")
|
||||||
|
.build();
|
||||||
|
|
||||||
var m = ctx.eval(code);
|
var m = ctx.eval(code);
|
||||||
var fac = m.invokeMember("eval_expression", "fac");
|
var fac = m.invokeMember("eval_expression", "fac");
|
||||||
var res = fac.execute(5);
|
var res = fac.execute(5);
|
||||||
assertEquals(120, res.asInt());
|
assertEquals(120, res.asInt());
|
||||||
|
|
||||||
var msgs = out.toString();
|
var msgs = out.toString();
|
||||||
assertNotEquals("Step one: " + msgs, -1, msgs.indexOf("n=5 v=1 acc=function"));
|
assertNotEquals("Step one: " + msgs, -1, msgs.indexOf("n=5 v=1 acc=function"));
|
||||||
assertNotEquals("Step two: " + msgs, -1, msgs.indexOf("n=4 v=5 acc=function"));
|
assertNotEquals("Step two: " + msgs, -1, msgs.indexOf("n=4 v=5 acc=function"));
|
||||||
assertNotEquals("3rd step: " + msgs, -1, msgs.indexOf("n=3 v=20 acc=function"));
|
assertNotEquals("3rd step: " + msgs, -1, msgs.indexOf("n=3 v=20 acc=function"));
|
||||||
assertNotEquals("4th step: " + msgs, -1, msgs.indexOf("n=2 v=60 acc=function"));
|
assertNotEquals("4th step: " + msgs, -1, msgs.indexOf("n=2 v=60 acc=function"));
|
||||||
|
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
"Uninitialized variables are seen as JavaScript null: " + msgs,
|
"Uninitialized variables are seen as JavaScript null: " + msgs,
|
||||||
-1, msgs.indexOf("n=null v=null acc=function")
|
-1,
|
||||||
);
|
msgs.indexOf("n=null v=null acc=function"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ public class JsInteropTest extends TestBase {
|
|||||||
ctx = createDefaultContext(out);
|
ctx = createDefaultContext(out);
|
||||||
out.reset();
|
out.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void disposeCtx() {
|
public void disposeCtx() {
|
||||||
ctx.close();
|
ctx.close();
|
||||||
@ -27,7 +27,8 @@ public class JsInteropTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultJSPrint() {
|
public void testDefaultJSPrint() {
|
||||||
var src = """
|
var src =
|
||||||
|
"""
|
||||||
from Standard.Base import Json
|
from Standard.Base import Json
|
||||||
|
|
||||||
main =
|
main =
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import org.enso.polyglot.RuntimeOptions;
|
import org.enso.polyglot.RuntimeOptions;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.Language;
|
import org.graalvm.polyglot.Language;
|
||||||
@ -9,13 +13,6 @@ import org.junit.Before;
|
|||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
public class NonStrictModeTests extends TestBase {
|
public class NonStrictModeTests extends TestBase {
|
||||||
private static Context nonStrictCtx;
|
private static Context nonStrictCtx;
|
||||||
private static MockLogHandler logHandler;
|
private static MockLogHandler logHandler;
|
||||||
@ -28,7 +25,10 @@ public class NonStrictModeTests extends TestBase {
|
|||||||
|
|
||||||
protected static Context createNonStrictContext() {
|
protected static Context createNonStrictContext() {
|
||||||
var context =
|
var context =
|
||||||
defaultContextBuilder().logHandler(logHandler).option(RuntimeOptions.STRICT_ERRORS, "false").build();
|
defaultContextBuilder()
|
||||||
|
.logHandler(logHandler)
|
||||||
|
.option(RuntimeOptions.STRICT_ERRORS, "false")
|
||||||
|
.build();
|
||||||
final Map<String, Language> langs = context.getEngine().getLanguages();
|
final Map<String, Language> langs = context.getEngine().getLanguages();
|
||||||
assertNotNull("Enso found: " + langs, langs.get("enso"));
|
assertNotNull("Enso found: " + langs, langs.get("enso"));
|
||||||
return context;
|
return context;
|
||||||
@ -46,15 +46,16 @@ public class NonStrictModeTests extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAmbiguousConversion() {
|
public void testAmbiguousConversion() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
type Bar
|
type Bar
|
||||||
Mk_Bar x
|
Mk_Bar x
|
||||||
|
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
||||||
|
|
||||||
main = 42
|
main = 42
|
||||||
""";
|
""";
|
||||||
Value res = evalModule(nonStrictCtx, src);
|
Value res = evalModule(nonStrictCtx, src);
|
||||||
@ -63,23 +64,25 @@ public class NonStrictModeTests extends TestBase {
|
|||||||
// Even if the conversion is unused and non-strict mode, we still get a diagnostic report:
|
// Even if the conversion is unused and non-strict mode, we still get a diagnostic report:
|
||||||
logHandler.assertMessage(
|
logHandler.assertMessage(
|
||||||
"enso.org.enso.compiler.Compiler",
|
"enso.org.enso.compiler.Compiler",
|
||||||
"Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in this module."
|
"Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in this"
|
||||||
);
|
+ " module.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAmbiguousConversionUsage() {
|
public void testAmbiguousConversionUsage() {
|
||||||
// In non-strict mode, the conversion declarations will have errors attached to the IR, but the overall operation
|
// In non-strict mode, the conversion declarations will have errors attached to the IR, but the
|
||||||
|
// overall operation
|
||||||
// will simply not see the second conversion and succeed with the first one.
|
// will simply not see the second conversion and succeed with the first one.
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
type Foo
|
type Foo
|
||||||
Mk_Foo data
|
Mk_Foo data
|
||||||
type Bar
|
type Bar
|
||||||
Mk_Bar x
|
Mk_Bar x
|
||||||
|
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+100
|
||||||
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
Foo.from (that:Bar) = Foo.Mk_Foo that.x+1000
|
||||||
|
|
||||||
main = (Foo.from (Bar.Mk_Bar 42)) . data
|
main = (Foo.from (Bar.Mk_Bar 42)) . data
|
||||||
""";
|
""";
|
||||||
|
|
||||||
@ -88,25 +91,27 @@ public class NonStrictModeTests extends TestBase {
|
|||||||
|
|
||||||
logHandler.assertMessage(
|
logHandler.assertMessage(
|
||||||
"enso.org.enso.compiler.Compiler",
|
"enso.org.enso.compiler.Compiler",
|
||||||
"Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in this module."
|
"Unnamed:7:1: error: Ambiguous conversion: Foo.from Bar is defined multiple times in this"
|
||||||
);
|
+ " module.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadImport() {
|
public void testBadImport() {
|
||||||
String src = """
|
String src = """
|
||||||
import That.Does.Not.Exist
|
import That.Does.Not.Exist
|
||||||
|
|
||||||
main = 2+2
|
main = 2+2
|
||||||
""";
|
""";
|
||||||
Value res = evalModule(nonStrictCtx, src);
|
Value res = evalModule(nonStrictCtx, src);
|
||||||
assertEquals(4, res.asInt());
|
assertEquals(4, res.asInt());
|
||||||
|
|
||||||
String line1 = "Unnamed:1:1: error: Package containing the module That.Does.Not.Exist could not be loaded: The " +
|
String line1 =
|
||||||
"package could not be resolved: The library `That.Does` is not defined within the edition.";
|
"Unnamed:1:1: error: Package containing the module That.Does.Not.Exist could not be loaded:"
|
||||||
|
+ " The package could not be resolved: The library `That.Does` is not defined within"
|
||||||
|
+ " the edition.";
|
||||||
String line2 = " 1 | import That.Does.Not.Exist";
|
String line2 = " 1 | import That.Does.Not.Exist";
|
||||||
String line3 = " | ^~~~~~~~~~~~~~~~~~~~~~~~~~";
|
String line3 = " | ^~~~~~~~~~~~~~~~~~~~~~~~~~";
|
||||||
logHandler.assertMessage("enso.org.enso.compiler.Compiler", line1 + "\n" + line2 + "\n" + line3);
|
logHandler.assertMessage(
|
||||||
|
"enso.org.enso.compiler.Compiler", line1 + "\n" + line2 + "\n" + line3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package org.enso.interpreter.test;
|
package org.enso.interpreter.test;
|
||||||
|
|
||||||
import org.enso.polyglot.HostEnsoUtils;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import org.enso.polyglot.HostEnsoUtils;
|
||||||
import org.graalvm.polyglot.Context;
|
import org.graalvm.polyglot.Context;
|
||||||
import org.graalvm.polyglot.PolyglotException;
|
import org.graalvm.polyglot.PolyglotException;
|
||||||
import org.graalvm.polyglot.Value;
|
import org.graalvm.polyglot.Value;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -26,7 +26,8 @@ public class PolyglotFindExceptionMessageTest extends TestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJavaScriptException() {
|
public void testJavaScriptException() {
|
||||||
String src = """
|
String src =
|
||||||
|
"""
|
||||||
main = err
|
main = err
|
||||||
|
|
||||||
foreign js err = \"""
|
foreign js err = \"""
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package org.enso.interpreter.test.instrument;
|
package org.enso.interpreter.test.instrument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.enso.interpreter.test.MockLogHandler;
|
import org.enso.interpreter.test.MockLogHandler;
|
||||||
import org.enso.polyglot.MethodNames;
|
import org.enso.polyglot.MethodNames;
|
||||||
import org.enso.polyglot.RuntimeOptions;
|
import org.enso.polyglot.RuntimeOptions;
|
||||||
@ -10,8 +12,6 @@ import org.graalvm.polyglot.Context;
|
|||||||
import org.graalvm.polyglot.Source;
|
import org.graalvm.polyglot.Source;
|
||||||
import org.graalvm.polyglot.io.IOAccess;
|
import org.graalvm.polyglot.io.IOAccess;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -45,8 +45,7 @@ public class VerifyLanguageAvailabilityTest {
|
|||||||
ctx.close();
|
ctx.close();
|
||||||
|
|
||||||
var args =
|
var args =
|
||||||
handler.assertMessage(
|
handler.assertMessage("epb.org.enso.interpreter.epb.EpbContext", "Parsing foreign script");
|
||||||
"epb.org.enso.interpreter.epb.EpbContext", "Parsing foreign script");
|
|
||||||
assertEquals("js", args[0]);
|
assertEquals("js", args[0]);
|
||||||
assertEquals("mul.mul", args[1]);
|
assertEquals("mul.mul", args[1]);
|
||||||
}
|
}
|
||||||
@ -55,12 +54,17 @@ public class VerifyLanguageAvailabilityTest {
|
|||||||
public void javaScriptIsPresent() throws Exception {
|
public void javaScriptIsPresent() throws Exception {
|
||||||
var js = ctx.getEngine().getLanguages().get("js");
|
var js = ctx.getEngine().getLanguages().get("js");
|
||||||
assertNotNull("JavaScript is available", js);
|
assertNotNull("JavaScript is available", js);
|
||||||
var src = Source.newBuilder("enso", """
|
var src =
|
||||||
|
Source.newBuilder(
|
||||||
|
"enso",
|
||||||
|
"""
|
||||||
foreign js mul a b = \"\"\"
|
foreign js mul a b = \"\"\"
|
||||||
return a * b
|
return a * b
|
||||||
|
|
||||||
run = mul 6 7
|
run = mul 6 7
|
||||||
""", "mul.enso").build();
|
""",
|
||||||
|
"mul.enso")
|
||||||
|
.build();
|
||||||
var fourtyTwo = ctx.eval(src).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "run");
|
var fourtyTwo = ctx.eval(src).invokeMember(MethodNames.Module.EVAL_EXPRESSION, "run");
|
||||||
assertEquals(42, fourtyTwo.asInt());
|
assertEquals(42, fourtyTwo.asInt());
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ public class ClassLoaderConstants {
|
|||||||
List.of("org.graalvm", "java", "org.slf4j", "ch.qos");
|
List.of("org.graalvm", "java", "org.slf4j", "ch.qos");
|
||||||
|
|
||||||
public static final List<String> RESOURCE_DELEGATION_PATTERNS = List.of("org.slf4j", "ch.qos");
|
public static final List<String> RESOURCE_DELEGATION_PATTERNS = List.of("org.slf4j", "ch.qos");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path to the {@code runner.jar} fat jar. This must not be on the system's module-path, because
|
* Path to the {@code runner.jar} fat jar. This must not be on the system's module-path, because
|
||||||
* the JVM would not be able to boot.
|
* the JVM would not be able to boot.
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
package org.enso.interpreter;
|
package org.enso.interpreter;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CallTarget;
|
||||||
|
import com.oracle.truffle.api.Option;
|
||||||
|
import com.oracle.truffle.api.TruffleLanguage;
|
||||||
|
import com.oracle.truffle.api.TruffleLogger;
|
||||||
|
import com.oracle.truffle.api.debug.DebuggerTags;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.instrumentation.ProvidedTags;
|
||||||
|
import com.oracle.truffle.api.instrumentation.StandardTags;
|
||||||
|
import com.oracle.truffle.api.nodes.ExecutableNode;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.enso.compiler.Compiler;
|
import org.enso.compiler.Compiler;
|
||||||
import org.enso.compiler.context.InlineContext;
|
import org.enso.compiler.context.InlineContext;
|
||||||
import org.enso.compiler.context.LocalScope;
|
import org.enso.compiler.context.LocalScope;
|
||||||
@ -41,18 +51,6 @@ import org.graalvm.options.OptionDescriptors;
|
|||||||
import org.graalvm.options.OptionKey;
|
import org.graalvm.options.OptionKey;
|
||||||
import org.graalvm.options.OptionType;
|
import org.graalvm.options.OptionType;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CallTarget;
|
|
||||||
import com.oracle.truffle.api.Option;
|
|
||||||
import com.oracle.truffle.api.TruffleLanguage;
|
|
||||||
import com.oracle.truffle.api.TruffleLogger;
|
|
||||||
import com.oracle.truffle.api.debug.DebuggerTags;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.instrumentation.ProvidedTags;
|
|
||||||
import com.oracle.truffle.api.instrumentation.StandardTags;
|
|
||||||
import com.oracle.truffle.api.nodes.ExecutableNode;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root of the Enso implementation.
|
* The root of the Enso implementation.
|
||||||
*
|
*
|
||||||
@ -72,8 +70,7 @@ import com.oracle.truffle.api.nodes.RootNode;
|
|||||||
contextPolicy = TruffleLanguage.ContextPolicy.EXCLUSIVE,
|
contextPolicy = TruffleLanguage.ContextPolicy.EXCLUSIVE,
|
||||||
dependentLanguages = {"epb"},
|
dependentLanguages = {"epb"},
|
||||||
fileTypeDetectors = FileDetector.class,
|
fileTypeDetectors = FileDetector.class,
|
||||||
services= { Timer.class, NotificationHandler.Forwarder.class, LockManager.class }
|
services = {Timer.class, NotificationHandler.Forwarder.class, LockManager.class})
|
||||||
)
|
|
||||||
@ProvidedTags({
|
@ProvidedTags({
|
||||||
DebuggerTags.AlwaysHalt.class,
|
DebuggerTags.AlwaysHalt.class,
|
||||||
StandardTags.CallTag.class,
|
StandardTags.CallTag.class,
|
||||||
@ -135,7 +132,6 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
env.registerService(lockManager);
|
env.registerService(lockManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boolean isExecutionTimerEnabled =
|
boolean isExecutionTimerEnabled =
|
||||||
env.getOptions().get(RuntimeOptions.ENABLE_EXECUTION_TIMER_KEY);
|
env.getOptions().get(RuntimeOptions.ENABLE_EXECUTION_TIMER_KEY);
|
||||||
Timer timer = isExecutionTimerEnabled ? new Timer.Nanosecond() : new Timer.Disabled();
|
Timer timer = isExecutionTimerEnabled ? new Timer.Nanosecond() : new Timer.Disabled();
|
||||||
@ -200,30 +196,28 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the given Enso source code snippet in {@code request}.
|
* Parses the given Enso source code snippet in {@code request}.
|
||||||
* <p>
|
*
|
||||||
* Inline parsing does not handle the following expressions:
|
* <p>Inline parsing does not handle the following expressions:
|
||||||
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Assignments</li>
|
* <li>Assignments
|
||||||
* <li>Imports and exports</li>
|
* <li>Imports and exports
|
||||||
* </ul>
|
* </ul>
|
||||||
* When given the aforementioned expressions in the request, {@code null}
|
*
|
||||||
* will be returned.
|
* When given the aforementioned expressions in the request, {@code null} will be returned.
|
||||||
*
|
*
|
||||||
* @param request request for inline parsing
|
* @param request request for inline parsing
|
||||||
* @throws InlineParsingException if the compiler failed to parse
|
* @throws InlineParsingException if the compiler failed to parse
|
||||||
* @return An {@link ExecutableNode} representing an AST fragment if the request contains
|
* @return An {@link ExecutableNode} representing an AST fragment if the request contains
|
||||||
* syntactically correct Enso source, {@code null} otherwise.
|
* syntactically correct Enso source, {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected ExecutableNode parse(InlineParsingRequest request) throws InlineParsingException {
|
protected ExecutableNode parse(InlineParsingRequest request) throws InlineParsingException {
|
||||||
if (request.getLocation().getRootNode() instanceof EnsoRootNode ensoRootNode) {
|
if (request.getLocation().getRootNode() instanceof EnsoRootNode ensoRootNode) {
|
||||||
var context = EnsoContext.get(request.getLocation());
|
var context = EnsoContext.get(request.getLocation());
|
||||||
Tree inlineExpr = context.getCompiler().parseInline(request.getSource());
|
Tree inlineExpr = context.getCompiler().parseInline(request.getSource());
|
||||||
var undesirableExprTypes = List.of(
|
var undesirableExprTypes =
|
||||||
Tree.Assignment.class,
|
List.of(Tree.Assignment.class, Tree.Import.class, Tree.Export.class);
|
||||||
Tree.Import.class,
|
|
||||||
Tree.Export.class
|
|
||||||
);
|
|
||||||
if (astContainsExprTypes(inlineExpr, undesirableExprTypes)) {
|
if (astContainsExprTypes(inlineExpr, undesirableExprTypes)) {
|
||||||
throw new InlineParsingException(
|
throw new InlineParsingException(
|
||||||
"Inline parsing request contains some of undesirable expression types: "
|
"Inline parsing request contains some of undesirable expression types: "
|
||||||
@ -231,50 +225,47 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
+ "\n"
|
+ "\n"
|
||||||
+ "Parsed expression: \n"
|
+ "Parsed expression: \n"
|
||||||
+ inlineExpr.codeRepr(),
|
+ inlineExpr.codeRepr(),
|
||||||
null
|
null);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var module = ensoRootNode.getModuleScope().getModule();
|
var module = ensoRootNode.getModuleScope().getModule();
|
||||||
var localScope = ensoRootNode.getLocalScope();
|
var localScope = ensoRootNode.getLocalScope();
|
||||||
var outputRedirect = new ByteArrayOutputStream();
|
var outputRedirect = new ByteArrayOutputStream();
|
||||||
var redirectConfigWithStrictErrors = new CompilerConfig(
|
var redirectConfigWithStrictErrors =
|
||||||
false,
|
new CompilerConfig(
|
||||||
false,
|
false, false, true, true, scala.Option.apply(new PrintStream(outputRedirect)));
|
||||||
true,
|
var moduleContext =
|
||||||
true,
|
new ModuleContext(
|
||||||
scala.Option.apply(new PrintStream(outputRedirect))
|
module.asCompilerModule(),
|
||||||
);
|
redirectConfigWithStrictErrors,
|
||||||
var moduleContext = new ModuleContext(
|
scala.Option.empty(),
|
||||||
module.asCompilerModule(), redirectConfigWithStrictErrors,
|
scala.Option.empty(),
|
||||||
scala.Option.empty(),
|
false,
|
||||||
scala.Option.empty(),
|
scala.Option.empty());
|
||||||
false,
|
var inlineContext =
|
||||||
scala.Option.empty()
|
new InlineContext(
|
||||||
);
|
moduleContext,
|
||||||
var inlineContext = new InlineContext(
|
redirectConfigWithStrictErrors,
|
||||||
moduleContext,
|
scala.Some.apply(localScope),
|
||||||
redirectConfigWithStrictErrors,
|
scala.Some.apply(false),
|
||||||
scala.Some.apply(localScope),
|
scala.Option.empty(),
|
||||||
scala.Some.apply(false),
|
scala.Option.empty(),
|
||||||
scala.Option.empty(),
|
scala.Option.empty());
|
||||||
scala.Option.empty(),
|
Compiler silentCompiler =
|
||||||
scala.Option.empty()
|
context.getCompiler().duplicateWithConfig(redirectConfigWithStrictErrors);
|
||||||
);
|
|
||||||
Compiler silentCompiler = context.getCompiler().duplicateWithConfig(redirectConfigWithStrictErrors);
|
|
||||||
ExpressionNode exprNode;
|
ExpressionNode exprNode;
|
||||||
try {
|
try {
|
||||||
var optionTupple = silentCompiler.runInline(
|
var optionTupple =
|
||||||
request.getSource().getCharacters().toString(),
|
silentCompiler.runInline(request.getSource().getCharacters().toString(), inlineContext);
|
||||||
inlineContext
|
|
||||||
);
|
|
||||||
if (optionTupple.nonEmpty()) {
|
if (optionTupple.nonEmpty()) {
|
||||||
var newInlineContext = optionTupple.get()._1();
|
var newInlineContext = optionTupple.get()._1();
|
||||||
var ir = optionTupple.get()._2();
|
var ir = optionTupple.get()._2();
|
||||||
var sco = newInlineContext.localScope().getOrElse(LocalScope::root);
|
var sco = newInlineContext.localScope().getOrElse(LocalScope::root);
|
||||||
var mod = newInlineContext.module$access$0().module$access$0();
|
var mod = newInlineContext.module$access$0().module$access$0();
|
||||||
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
|
var m = org.enso.interpreter.runtime.Module.fromCompilerModule(mod);
|
||||||
var toTruffle = new IrToTruffle(context, request.getSource(), m.getScope(), redirectConfigWithStrictErrors);
|
var toTruffle =
|
||||||
|
new IrToTruffle(
|
||||||
|
context, request.getSource(), m.getScope(), redirectConfigWithStrictErrors);
|
||||||
exprNode = toTruffle.runInline(ir, sco, "<inline_source>");
|
exprNode = toTruffle.runInline(ir, sco, "<inline_source>");
|
||||||
} else {
|
} else {
|
||||||
exprNode = null;
|
exprNode = null;
|
||||||
@ -282,7 +273,8 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
} catch (UnhandledEntity e) {
|
} catch (UnhandledEntity e) {
|
||||||
throw new InlineParsingException("Unhandled entity: " + e.entity(), e);
|
throw new InlineParsingException("Unhandled entity: " + e.entity(), e);
|
||||||
} catch (CompilationAbortedException e) {
|
} catch (CompilationAbortedException e) {
|
||||||
assert outputRedirect.toString().lines().count() > 1 : "Expected a header line from the compiler";
|
assert outputRedirect.toString().lines().count() > 1
|
||||||
|
: "Expected a header line from the compiler";
|
||||||
String compilerErrOutput = outputRedirect.toString();
|
String compilerErrOutput = outputRedirect.toString();
|
||||||
throw new InlineParsingException(compilerErrOutput, e);
|
throw new InlineParsingException(compilerErrOutput, e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -292,8 +284,7 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
if (exprNode != null) {
|
if (exprNode != null) {
|
||||||
var language = EnsoLanguage.get(exprNode);
|
var language = EnsoLanguage.get(exprNode);
|
||||||
return new ExecutableNode(language) {
|
return new ExecutableNode(language) {
|
||||||
@Child
|
@Child private ExpressionNode expr;
|
||||||
private ExpressionNode expr;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object execute(VirtualFrame frame) {
|
public Object execute(VirtualFrame frame) {
|
||||||
@ -314,19 +305,14 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns true if the given ast transitively contains any of {@code exprTypes}. */
|
||||||
* Returns true if the given ast transitively contains any of {@code exprTypes}.
|
|
||||||
*/
|
|
||||||
private boolean astContainsExprTypes(Tree ast, List<Class<? extends Tree>> exprTypes) {
|
private boolean astContainsExprTypes(Tree ast, List<Class<? extends Tree>> exprTypes) {
|
||||||
boolean astMatchesExprType = exprTypes
|
boolean astMatchesExprType =
|
||||||
.stream()
|
exprTypes.stream().anyMatch(exprType -> exprType.equals(ast.getClass()));
|
||||||
.anyMatch(exprType -> exprType.equals(ast.getClass()));
|
|
||||||
if (astMatchesExprType) {
|
if (astMatchesExprType) {
|
||||||
return true;
|
return true;
|
||||||
} else if (ast instanceof Tree.BodyBlock block) {
|
} else if (ast instanceof Tree.BodyBlock block) {
|
||||||
return block
|
return block.getStatements().stream()
|
||||||
.getStatements()
|
|
||||||
.stream()
|
|
||||||
.map(Line::getExpression)
|
.map(Line::getExpression)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.anyMatch((Tree expr) -> astContainsExprTypes(expr, exprTypes));
|
.anyMatch((Tree expr) -> astContainsExprTypes(expr, exprTypes));
|
||||||
@ -336,13 +322,13 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
name = "ExecutionEnvironment",
|
name = "ExecutionEnvironment",
|
||||||
category = OptionCategory.USER,
|
category = OptionCategory.USER,
|
||||||
help = "The environment for program execution. Defaults to `design`.")
|
help = "The environment for program execution. Defaults to `design`.")
|
||||||
public static final OptionKey<ExecutionEnvironment> EXECUTION_ENVIRONMENT =
|
public static final OptionKey<ExecutionEnvironment> EXECUTION_ENVIRONMENT =
|
||||||
new OptionKey<>(
|
new OptionKey<>(
|
||||||
ExecutionEnvironment.DESIGN, new OptionType<>("ExecutionEnvironment", ExecutionEnvironment::forName));
|
ExecutionEnvironment.DESIGN,
|
||||||
|
new OptionType<>("ExecutionEnvironment", ExecutionEnvironment::forName));
|
||||||
|
|
||||||
private static final OptionDescriptors OPTIONS =
|
private static final OptionDescriptors OPTIONS =
|
||||||
OptionDescriptors.createUnion(
|
OptionDescriptors.createUnion(
|
||||||
@ -367,7 +353,7 @@ public final class EnsoLanguage extends TruffleLanguage<EnsoContext> {
|
|||||||
|
|
||||||
/** Conversions of primitive values */
|
/** Conversions of primitive values */
|
||||||
protected Object getLanguageView(EnsoContext context, Object value) {
|
protected Object getLanguageView(EnsoContext context, Object value) {
|
||||||
if (value instanceof Boolean b ) {
|
if (value instanceof Boolean b) {
|
||||||
var bool = context.getBuiltins().bool();
|
var bool = context.getBuiltins().bool();
|
||||||
return b ? bool.getTrue().newInstance() : bool.getFalse().newInstance();
|
return b ? bool.getTrue().newInstance() : bool.getFalse().newInstance();
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ public abstract class Cache<T, M extends Cache.Metadata> {
|
|||||||
|
|
||||||
/** Returns a default level of logging for this Cache. */
|
/** Returns a default level of logging for this Cache. */
|
||||||
protected final Level logLevel;
|
protected final Level logLevel;
|
||||||
|
|
||||||
/** Log name to use in log messages */
|
/** Log name to use in log messages */
|
||||||
private final String logName;
|
private final String logName;
|
||||||
|
|
||||||
|
@ -1,197 +1,215 @@
|
|||||||
package org.enso.interpreter.caches;
|
package org.enso.interpreter.caches;
|
||||||
|
|
||||||
import java.io.IOException;
|
import buildinfo.Info;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.enso.persist.Persistance;
|
|
||||||
import org.enso.persist.Persistable;
|
|
||||||
import org.enso.compiler.data.BindingsMap;
|
|
||||||
import org.enso.compiler.data.BindingsMap.DefinedEntity;
|
|
||||||
import org.enso.compiler.data.BindingsMap.ModuleReference;
|
|
||||||
import org.enso.editions.LibraryName;
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.pkg.QualifiedName;
|
|
||||||
import org.enso.pkg.SourceFile;
|
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.oracle.truffle.api.TruffleFile;
|
import com.oracle.truffle.api.TruffleFile;
|
||||||
import com.oracle.truffle.api.TruffleLogger;
|
import com.oracle.truffle.api.TruffleLogger;
|
||||||
|
import java.io.IOException;
|
||||||
import buildinfo.Info;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.enso.compiler.data.BindingsMap;
|
||||||
|
import org.enso.compiler.data.BindingsMap.DefinedEntity;
|
||||||
|
import org.enso.compiler.data.BindingsMap.ModuleReference;
|
||||||
|
import org.enso.editions.LibraryName;
|
||||||
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
|
import org.enso.persist.Persistable;
|
||||||
|
import org.enso.persist.Persistance;
|
||||||
|
import org.enso.pkg.QualifiedName;
|
||||||
|
import org.enso.pkg.SourceFile;
|
||||||
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import scala.Option;
|
import scala.Option;
|
||||||
import scala.Tuple2;
|
import scala.Tuple2;
|
||||||
import scala.collection.immutable.Map;
|
import scala.collection.immutable.Map;
|
||||||
|
|
||||||
@Persistable(clazz = QualifiedName.class, id = 30300)
|
@Persistable(clazz = QualifiedName.class, id = 30300)
|
||||||
public final class ImportExportCache extends Cache<ImportExportCache.CachedBindings, ImportExportCache.Metadata> {
|
public final class ImportExportCache
|
||||||
|
extends Cache<ImportExportCache.CachedBindings, ImportExportCache.Metadata> {
|
||||||
|
|
||||||
private final LibraryName libraryName;
|
private final LibraryName libraryName;
|
||||||
|
|
||||||
public ImportExportCache(LibraryName libraryName) {
|
public ImportExportCache(LibraryName libraryName) {
|
||||||
super(Level.FINEST, libraryName.toString(), true, false);
|
super(Level.FINEST, libraryName.toString(), true, false);
|
||||||
this.libraryName = libraryName;
|
this.libraryName = libraryName;
|
||||||
this.entryName = libraryName.name();
|
this.entryName = libraryName.name();
|
||||||
this.dataSuffix = bindingsCacheDataExtension;
|
this.dataSuffix = bindingsCacheDataExtension;
|
||||||
this.metadataSuffix = bindingsCacheMetadataExtension;
|
this.metadataSuffix = bindingsCacheMetadataExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] metadata(String sourceDigest, String blobDigest, CachedBindings entry) {
|
||||||
|
try {
|
||||||
|
return objectMapper
|
||||||
|
.writeValueAsString(new Metadata(sourceDigest, blobDigest))
|
||||||
|
.getBytes(metadataCharset);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] metadata(String sourceDigest, String blobDigest, CachedBindings entry) {
|
protected CachedBindings deserialize(
|
||||||
try {
|
EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger)
|
||||||
return objectMapper.writeValueAsString(new Metadata(sourceDigest, blobDigest)).getBytes(metadataCharset);
|
throws ClassNotFoundException, IOException, ClassNotFoundException {
|
||||||
} catch (JsonProcessingException e) {
|
var ref = Persistance.read(data, null);
|
||||||
throw new RuntimeException(e);
|
var bindings = ref.get(MapToBindings.class);
|
||||||
}
|
return new CachedBindings(libraryName, bindings, Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CachedBindings deserialize(EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger) throws ClassNotFoundException, IOException, ClassNotFoundException {
|
protected Optional<Metadata> metadataFromBytes(byte[] bytes, TruffleLogger logger) {
|
||||||
var ref = Persistance.read(data, null);
|
var maybeJsonString = new String(bytes, Cache.metadataCharset);
|
||||||
var bindings = ref.get(MapToBindings.class);
|
var mapper = new ObjectMapper();
|
||||||
return new CachedBindings(libraryName, bindings, Optional.empty());
|
try {
|
||||||
|
return Optional.of(objectMapper.readValue(maybeJsonString, ImportExportCache.Metadata.class));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
logger.log(logLevel, "Failed to deserialize library's metadata.", e);
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<Metadata> metadataFromBytes(byte[] bytes, TruffleLogger logger) {
|
protected Optional<String> computeDigest(CachedBindings entry, TruffleLogger logger) {
|
||||||
var maybeJsonString = new String(bytes, Cache.metadataCharset);
|
return entry.sources().map(sources -> computeDigestOfLibrarySources(sources, logger));
|
||||||
var mapper = new ObjectMapper();
|
}
|
||||||
try {
|
|
||||||
return Optional.of(objectMapper.readValue(maybeJsonString, ImportExportCache.Metadata.class));
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
logger.log(logLevel, "Failed to deserialize library's metadata.", e);
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<String> computeDigest(CachedBindings entry, TruffleLogger logger) {
|
@SuppressWarnings("unchecked")
|
||||||
return entry.sources().map(sources -> computeDigestOfLibrarySources(sources, logger));
|
protected Optional<String> computeDigestFromSource(EnsoContext context, TruffleLogger logger) {
|
||||||
}
|
return context
|
||||||
@Override
|
.getPackageRepository()
|
||||||
@SuppressWarnings("unchecked")
|
.getPackageForLibraryJava(libraryName)
|
||||||
protected Optional<String> computeDigestFromSource(EnsoContext context, TruffleLogger logger) {
|
.map(pkg -> computeDigestOfLibrarySources(pkg.listSourcesJava(), logger));
|
||||||
return context
|
}
|
||||||
.getPackageRepository()
|
|
||||||
.getPackageForLibraryJava(libraryName)
|
|
||||||
.map(pkg -> computeDigestOfLibrarySources(pkg.listSourcesJava(), logger));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected Optional<Cache.Roots> getCacheRoots(EnsoContext context) {
|
protected Optional<Cache.Roots> getCacheRoots(EnsoContext context) {
|
||||||
return context.getPackageRepository().getPackageForLibraryJava(libraryName).map(pkg -> {
|
return context
|
||||||
var bindingsCacheRoot =
|
.getPackageRepository()
|
||||||
pkg.getBindingsCacheRootForPackage(Info.ensoVersion());
|
.getPackageForLibraryJava(libraryName)
|
||||||
var localCacheRoot = bindingsCacheRoot.resolve(libraryName.namespace());
|
.map(
|
||||||
var distribution = context.getDistributionManager();
|
pkg -> {
|
||||||
var pathSegments = new String[]{
|
var bindingsCacheRoot = pkg.getBindingsCacheRootForPackage(Info.ensoVersion());
|
||||||
|
var localCacheRoot = bindingsCacheRoot.resolve(libraryName.namespace());
|
||||||
|
var distribution = context.getDistributionManager();
|
||||||
|
var pathSegments =
|
||||||
|
new String[] {
|
||||||
pkg.namespace(),
|
pkg.namespace(),
|
||||||
pkg.normalizedName(),
|
pkg.normalizedName(),
|
||||||
pkg.getConfig().version(),
|
pkg.getConfig().version(),
|
||||||
Info.ensoVersion(),
|
Info.ensoVersion(),
|
||||||
libraryName.namespace()
|
libraryName.namespace()
|
||||||
};
|
};
|
||||||
var path = distribution.LocallyInstalledDirectories().irCacheDirectory()
|
var path =
|
||||||
.resolve(StringUtils.join(pathSegments, "/"));
|
distribution.LocallyInstalledDirectories()
|
||||||
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
.irCacheDirectory()
|
||||||
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
.resolve(StringUtils.join(pathSegments, "/"));
|
||||||
});
|
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
||||||
|
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] serialize(EnsoContext context, CachedBindings entry) throws IOException {
|
||||||
|
var arr = Persistance.write(entry.bindings(), null);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class MapToBindings {
|
||||||
|
private final Map<QualifiedName, Persistance.Reference<BindingsMap>> entries;
|
||||||
|
|
||||||
|
public MapToBindings(Map<QualifiedName, Persistance.Reference<BindingsMap>> entries) {
|
||||||
|
this.entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Option<BindingsMap> findForModule(QualifiedName moduleName) {
|
||||||
|
var ref = entries.get(moduleName);
|
||||||
|
if (ref.isEmpty()) {
|
||||||
|
return Option.empty();
|
||||||
|
}
|
||||||
|
return Option.apply(ref.get().get(BindingsMap.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceProvider(service = Persistance.class)
|
||||||
|
public static final class PersistMapToBindings extends Persistance<MapToBindings> {
|
||||||
|
public PersistMapToBindings() {
|
||||||
|
super(MapToBindings.class, false, 364);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] serialize(EnsoContext context, CachedBindings entry) throws IOException {
|
protected void writeObject(MapToBindings obj, Output out) throws IOException {
|
||||||
var arr = Persistance.write(entry.bindings(), null);
|
out.writeInt(obj.entries.size());
|
||||||
return arr;
|
var it = obj.entries.iterator();
|
||||||
}
|
while (it.hasNext()) {
|
||||||
|
var e = it.next();
|
||||||
public static final class MapToBindings {
|
out.writeInline(QualifiedName.class, e._1());
|
||||||
private final Map<QualifiedName, Persistance.Reference<BindingsMap>> entries;
|
out.writeObject(e._2().get(BindingsMap.class));
|
||||||
|
|
||||||
public MapToBindings(Map<QualifiedName, Persistance.Reference<BindingsMap>> entries) {
|
|
||||||
this.entries = entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option<BindingsMap> findForModule(QualifiedName moduleName) {
|
|
||||||
var ref = entries.get(moduleName);
|
|
||||||
if (ref.isEmpty()) {
|
|
||||||
return Option.empty();
|
|
||||||
}
|
|
||||||
return Option.apply(ref.get().get(BindingsMap.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ServiceProvider(service = Persistance.class)
|
|
||||||
public static final class PersistMapToBindings extends Persistance<MapToBindings> {
|
|
||||||
public PersistMapToBindings() {
|
|
||||||
super(MapToBindings.class, false, 364);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writeObject(MapToBindings obj, Output out) throws IOException {
|
|
||||||
out.writeInt(obj.entries.size());
|
|
||||||
var it = obj.entries.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
var e = it.next();
|
|
||||||
out.writeInline(QualifiedName.class, e._1());
|
|
||||||
out.writeObject(e._2().get(BindingsMap.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected MapToBindings readObject(Input in) throws IOException, ClassNotFoundException {
|
|
||||||
var size = in.readInt();
|
|
||||||
var b = Map.newBuilder();
|
|
||||||
b.sizeHint(size);
|
|
||||||
while (size-- > 0) {
|
|
||||||
var name = in.readInline(QualifiedName.class);
|
|
||||||
var value = in.readReference(BindingsMap.class);
|
|
||||||
b.addOne(Tuple2.apply(name, value));
|
|
||||||
}
|
|
||||||
return new MapToBindings((Map) b.result());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static record CachedBindings(LibraryName libraryName, MapToBindings bindings, Optional<List<SourceFile<TruffleFile>>> sources) {
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected MapToBindings readObject(Input in) throws IOException, ClassNotFoundException {
|
||||||
|
var size = in.readInt();
|
||||||
|
var b = Map.newBuilder();
|
||||||
|
b.sizeHint(size);
|
||||||
|
while (size-- > 0) {
|
||||||
|
var name = in.readInline(QualifiedName.class);
|
||||||
|
var value = in.readReference(BindingsMap.class);
|
||||||
|
b.addOne(Tuple2.apply(name, value));
|
||||||
|
}
|
||||||
|
return new MapToBindings((Map) b.result());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public record Metadata(
|
public static record CachedBindings(
|
||||||
@JsonProperty("source_hash") String sourceHash,
|
LibraryName libraryName,
|
||||||
@JsonProperty("blob_hash") String blobHash) implements Cache.Metadata {}
|
MapToBindings bindings,
|
||||||
|
Optional<List<SourceFile<TruffleFile>>> sources) {}
|
||||||
|
|
||||||
private static final String bindingsCacheDataExtension = ".bindings";
|
public record Metadata(
|
||||||
|
@JsonProperty("source_hash") String sourceHash, @JsonProperty("blob_hash") String blobHash)
|
||||||
|
implements Cache.Metadata {}
|
||||||
|
|
||||||
private static final String bindingsCacheMetadataExtension =".bindings.meta";
|
private static final String bindingsCacheDataExtension = ".bindings";
|
||||||
|
|
||||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
private static final String bindingsCacheMetadataExtension = ".bindings.meta";
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@Persistable(clazz=BindingsMap.PolyglotSymbol.class, id=33006)
|
@Persistable(clazz = BindingsMap.PolyglotSymbol.class, id = 33006)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$ModuleReference$Abstract.class, id=33007)
|
@Persistable(
|
||||||
@Persistable(clazz=BindingsMap.ModuleMethod.class, id=33008)
|
clazz = org.enso.compiler.data.BindingsMap$ModuleReference$Abstract.class,
|
||||||
@Persistable(clazz=BindingsMap.Type.class, id=33009)
|
id = 33007)
|
||||||
@Persistable(clazz=BindingsMap.ResolvedImport.class, id=33010)
|
@Persistable(clazz = BindingsMap.ModuleMethod.class, id = 33008)
|
||||||
@Persistable(clazz=BindingsMap.Cons.class, id=33011)
|
@Persistable(clazz = BindingsMap.Type.class, id = 33009)
|
||||||
@Persistable(clazz=BindingsMap.ResolvedModule.class, id=33012)
|
@Persistable(clazz = BindingsMap.ResolvedImport.class, id = 33010)
|
||||||
@Persistable(clazz=BindingsMap.ResolvedType.class, id=33013)
|
@Persistable(clazz = BindingsMap.Cons.class, id = 33011)
|
||||||
@Persistable(clazz=BindingsMap.ResolvedMethod.class, id=33014)
|
@Persistable(clazz = BindingsMap.ResolvedModule.class, id = 33012)
|
||||||
@Persistable(clazz=BindingsMap.ExportedModule.class, id=33015)
|
@Persistable(clazz = BindingsMap.ResolvedType.class, id = 33013)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$Only.class, id=33016)
|
@Persistable(clazz = BindingsMap.ResolvedMethod.class, id = 33014)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$Union.class, id=33017)
|
@Persistable(clazz = BindingsMap.ExportedModule.class, id = 33015)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$Intersect.class, id=33018)
|
@Persistable(clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$Only.class, id = 33016)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$AllowedResolution.class, id=33019)
|
@Persistable(clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$Union.class, id = 33017)
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$All$.class, id=33020)
|
@Persistable(
|
||||||
@Persistable(clazz=org.enso.compiler.data.BindingsMap$SymbolRestriction$Hiding.class, id=33021)
|
clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$Intersect.class,
|
||||||
@Persistable(clazz=BindingsMap.Resolution.class, id=33029)
|
id = 33018)
|
||||||
@Persistable(clazz=BindingsMap.ResolvedConstructor.class, id=33030)
|
@Persistable(
|
||||||
@Persistable(clazz=BindingsMap.ResolvedPolyglotSymbol.class, id=33031)
|
clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$AllowedResolution.class,
|
||||||
@Persistable(clazz=BindingsMap.ResolvedPolyglotField.class, id=33032)
|
id = 33019)
|
||||||
|
@Persistable(clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$All$.class, id = 33020)
|
||||||
|
@Persistable(
|
||||||
|
clazz = org.enso.compiler.data.BindingsMap$SymbolRestriction$Hiding.class,
|
||||||
|
id = 33021)
|
||||||
|
@Persistable(clazz = BindingsMap.Resolution.class, id = 33029)
|
||||||
|
@Persistable(clazz = BindingsMap.ResolvedConstructor.class, id = 33030)
|
||||||
|
@Persistable(clazz = BindingsMap.ResolvedPolyglotSymbol.class, id = 33031)
|
||||||
|
@Persistable(clazz = BindingsMap.ResolvedPolyglotField.class, id = 33032)
|
||||||
@ServiceProvider(service = Persistance.class)
|
@ServiceProvider(service = Persistance.class)
|
||||||
public static final class PersistBindingsMap extends Persistance<BindingsMap> {
|
public static final class PersistBindingsMap extends Persistance<BindingsMap> {
|
||||||
public PersistBindingsMap() {
|
public PersistBindingsMap() {
|
||||||
@ -222,6 +240,4 @@ public final class ImportExportCache extends Cache<ImportExportCache.CachedBindi
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,172 +1,186 @@
|
|||||||
package org.enso.interpreter.caches;
|
package org.enso.interpreter.caches;
|
||||||
|
|
||||||
import buildinfo.Info;
|
import buildinfo.Info;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.oracle.truffle.api.TruffleLogger;
|
import com.oracle.truffle.api.TruffleLogger;
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.enso.compiler.core.ir.Module;
|
|
||||||
import org.enso.compiler.core.ir.ProcessingPass;
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.interpreter.runtime.builtin.Builtins;
|
|
||||||
import org.enso.polyglot.CompilationStage;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.enso.compiler.core.ir.Module;
|
||||||
|
import org.enso.compiler.core.ir.ProcessingPass;
|
||||||
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
|
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||||
import org.enso.persist.Persistance;
|
import org.enso.persist.Persistance;
|
||||||
|
import org.enso.polyglot.CompilationStage;
|
||||||
|
|
||||||
public final class ModuleCache extends Cache<ModuleCache.CachedModule, ModuleCache.Metadata> {
|
public final class ModuleCache extends Cache<ModuleCache.CachedModule, ModuleCache.Metadata> {
|
||||||
|
|
||||||
private final org.enso.interpreter.runtime.Module module;
|
private final org.enso.interpreter.runtime.Module module;
|
||||||
|
|
||||||
public ModuleCache(org.enso.interpreter.runtime.Module module) {
|
public ModuleCache(org.enso.interpreter.runtime.Module module) {
|
||||||
super(Level.FINEST, module.getName().toString(), true, false);
|
super(Level.FINEST, module.getName().toString(), true, false);
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.entryName = module.getName().item();
|
this.entryName = module.getName().item();
|
||||||
this.dataSuffix = irCacheDataExtension;
|
this.dataSuffix = irCacheDataExtension;
|
||||||
this.metadataSuffix = irCacheMetadataExtension;
|
this.metadataSuffix = irCacheMetadataExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] metadata(String sourceDigest, String blobDigest, CachedModule entry) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsBytes(
|
||||||
|
new Metadata(sourceDigest, blobDigest, entry.compilationStage().toString()));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] metadata(String sourceDigest, String blobDigest, CachedModule entry) {
|
protected CachedModule deserialize(
|
||||||
try {
|
EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger)
|
||||||
return objectMapper.writeValueAsBytes(new Metadata(sourceDigest, blobDigest, entry.compilationStage().toString()));
|
throws ClassNotFoundException, IOException, ClassNotFoundException {
|
||||||
} catch (JsonProcessingException e) {
|
var ref =
|
||||||
throw new RuntimeException(e);
|
Persistance.read(
|
||||||
}
|
data,
|
||||||
|
(obj) ->
|
||||||
|
switch (obj) {
|
||||||
|
case ProcessingPass.Metadata metadata -> {
|
||||||
|
var option = metadata.restoreFromSerialization(context.getCompiler().context());
|
||||||
|
if (option.nonEmpty()) {
|
||||||
|
yield option.get();
|
||||||
|
} else {
|
||||||
|
throw raise(
|
||||||
|
RuntimeException.class, new IOException("Cannot convert " + metadata));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> obj;
|
||||||
|
});
|
||||||
|
var mod = ref.get(Module.class);
|
||||||
|
return new CachedModule(
|
||||||
|
mod, CompilationStage.valueOf(meta.compilationStage()), module.getSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<Metadata> metadataFromBytes(byte[] bytes, TruffleLogger logger) {
|
||||||
|
var maybeJsonString = new String(bytes, Cache.metadataCharset);
|
||||||
|
try {
|
||||||
|
return Optional.of(objectMapper.readValue(maybeJsonString, Metadata.class));
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
logger.log(logLevel, "Failed to deserialize module's metadata.", e);
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private Optional<String> computeDigestOfModuleSources(Source source) {
|
||||||
protected CachedModule deserialize(EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger) throws ClassNotFoundException, IOException, ClassNotFoundException {
|
if (source != null) {
|
||||||
var ref = Persistance.read(data, (obj) -> switch (obj) {
|
byte[] sourceBytes;
|
||||||
case ProcessingPass.Metadata metadata -> {
|
if (source.hasBytes()) {
|
||||||
var option = metadata.restoreFromSerialization(context.getCompiler().context());
|
sourceBytes = source.getBytes().toByteArray();
|
||||||
if (option.nonEmpty()) {
|
} else {
|
||||||
yield option.get();
|
sourceBytes = source.getCharacters().toString().getBytes(metadataCharset);
|
||||||
} else {
|
}
|
||||||
throw raise(RuntimeException.class, new IOException("Cannot convert " + metadata));
|
return Optional.of(computeDigestFromBytes(sourceBytes));
|
||||||
}
|
} else {
|
||||||
}
|
return Optional.empty();
|
||||||
default -> obj;
|
|
||||||
});
|
|
||||||
var mod = ref.get(Module.class);
|
|
||||||
return new CachedModule(mod, CompilationStage.valueOf(meta.compilationStage()), module.getSource());
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<Metadata> metadataFromBytes(byte[] bytes, TruffleLogger logger) {
|
protected Optional<String> computeDigest(CachedModule entry, TruffleLogger logger) {
|
||||||
var maybeJsonString = new String(bytes, Cache.metadataCharset);
|
return computeDigestOfModuleSources(entry.source());
|
||||||
try {
|
}
|
||||||
return Optional.of(objectMapper.readValue(maybeJsonString, Metadata.class));
|
|
||||||
} catch (JsonProcessingException e) {
|
@Override
|
||||||
logger.log(logLevel, "Failed to deserialize module's metadata.", e);
|
protected Optional<String> computeDigestFromSource(EnsoContext context, TruffleLogger logger) {
|
||||||
return Optional.empty();
|
try {
|
||||||
}
|
return computeDigestOfModuleSources(module.getSource());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(logLevel, "failed to retrieve the source of " + module.getName(), e);
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Optional<String> computeDigestOfModuleSources(Source source) {
|
@Override
|
||||||
if (source != null) {
|
protected Optional<Cache.Roots> getCacheRoots(EnsoContext context) {
|
||||||
byte[] sourceBytes;
|
if (module != context.getBuiltins().getModule()) {
|
||||||
if (source.hasBytes()) {
|
return context
|
||||||
sourceBytes = source.getBytes().toByteArray();
|
.getPackageOf(module.getSourceFile())
|
||||||
} else {
|
.map(
|
||||||
sourceBytes = source.getCharacters().toString().getBytes(metadataCharset);
|
pkg -> {
|
||||||
}
|
var irCacheRoot = pkg.getIrCacheRootForPackage(Info.ensoVersion());
|
||||||
return Optional.of(computeDigestFromBytes(sourceBytes));
|
var qualName = module.getName();
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Optional<String> computeDigest(CachedModule entry, TruffleLogger logger) {
|
|
||||||
return computeDigestOfModuleSources(entry.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Optional<String> computeDigestFromSource(EnsoContext context, TruffleLogger logger) {
|
|
||||||
try {
|
|
||||||
return computeDigestOfModuleSources(module.getSource());
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.log(logLevel, "failed to retrieve the source of " + module.getName(), e);
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Optional<Cache.Roots> getCacheRoots(EnsoContext context) {
|
|
||||||
if (module != context.getBuiltins().getModule()) {
|
|
||||||
return context.getPackageOf(module.getSourceFile()).map(pkg -> {
|
|
||||||
var irCacheRoot = pkg.getIrCacheRootForPackage(Info.ensoVersion());
|
|
||||||
var qualName = module.getName();
|
|
||||||
var localCacheRoot = irCacheRoot.resolve(qualName.path().mkString("/"));
|
var localCacheRoot = irCacheRoot.resolve(qualName.path().mkString("/"));
|
||||||
|
|
||||||
var distribution = context.getDistributionManager();
|
var distribution = context.getDistributionManager();
|
||||||
var pathSegmentsJava = new ArrayList<String>();
|
var pathSegmentsJava = new ArrayList<String>();
|
||||||
pathSegmentsJava.addAll(Arrays.asList(
|
pathSegmentsJava.addAll(
|
||||||
|
Arrays.asList(
|
||||||
pkg.namespace(),
|
pkg.namespace(),
|
||||||
pkg.normalizedName(),
|
pkg.normalizedName(),
|
||||||
pkg.getConfig().version(),
|
pkg.getConfig().version(),
|
||||||
Info.ensoVersion()
|
Info.ensoVersion()));
|
||||||
));
|
|
||||||
pathSegmentsJava.addAll(qualName.pathAsJava());
|
pathSegmentsJava.addAll(qualName.pathAsJava());
|
||||||
var path = distribution.LocallyInstalledDirectories().irCacheDirectory()
|
var path =
|
||||||
|
distribution.LocallyInstalledDirectories()
|
||||||
|
.irCacheDirectory()
|
||||||
.resolve(StringUtils.join(pathSegmentsJava, "/"));
|
.resolve(StringUtils.join(pathSegmentsJava, "/"));
|
||||||
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
||||||
|
|
||||||
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
var distribution = context.getDistributionManager();
|
var distribution = context.getDistributionManager();
|
||||||
var pathSegmentsJava = new ArrayList<String>();
|
var pathSegmentsJava = new ArrayList<String>();
|
||||||
pathSegmentsJava.addAll(Arrays.asList(
|
pathSegmentsJava.addAll(
|
||||||
Builtins.NAMESPACE,
|
Arrays.asList(
|
||||||
Builtins.PACKAGE_NAME,
|
Builtins.NAMESPACE, Builtins.PACKAGE_NAME, Info.ensoVersion(), Info.ensoVersion()));
|
||||||
Info.ensoVersion(),
|
pathSegmentsJava.addAll(module.getName().pathAsJava());
|
||||||
Info.ensoVersion()
|
var path =
|
||||||
));
|
distribution.LocallyInstalledDirectories()
|
||||||
pathSegmentsJava.addAll(module.getName().pathAsJava());
|
.irCacheDirectory()
|
||||||
var path = distribution.LocallyInstalledDirectories().irCacheDirectory()
|
.resolve(StringUtils.join(pathSegmentsJava, "/"));
|
||||||
.resolve(StringUtils.join(pathSegmentsJava, "/"));
|
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
||||||
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
|
||||||
|
|
||||||
return Optional.of(new Cache.Roots(globalCacheRoot, globalCacheRoot));
|
return Optional.of(new Cache.Roots(globalCacheRoot, globalCacheRoot));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] serialize(EnsoContext context, CachedModule entry) throws IOException {
|
protected byte[] serialize(EnsoContext context, CachedModule entry) throws IOException {
|
||||||
var arr = Persistance.write(entry.moduleIR(), (obj) -> switch (obj) {
|
var arr =
|
||||||
case ProcessingPass.Metadata metadata -> metadata.prepareForSerialization(context.getCompiler().context());
|
Persistance.write(
|
||||||
default -> obj;
|
entry.moduleIR(),
|
||||||
});
|
(obj) ->
|
||||||
return arr;
|
switch (obj) {
|
||||||
}
|
case ProcessingPass.Metadata metadata -> metadata.prepareForSerialization(
|
||||||
|
context.getCompiler().context());
|
||||||
|
default -> obj;
|
||||||
|
});
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
public record CachedModule(Module moduleIR, CompilationStage compilationStage, Source source) {
|
public record CachedModule(Module moduleIR, CompilationStage compilationStage, Source source) {}
|
||||||
}
|
|
||||||
|
|
||||||
public record Metadata(
|
public record Metadata(
|
||||||
@JsonProperty("source_hash") String sourceHash,
|
@JsonProperty("source_hash") String sourceHash,
|
||||||
@JsonProperty("blob_hash") String blobHash,
|
@JsonProperty("blob_hash") String blobHash,
|
||||||
@JsonProperty("compilation_stage") String compilationStage) implements Cache.Metadata {}
|
@JsonProperty("compilation_stage") String compilationStage)
|
||||||
|
implements Cache.Metadata {}
|
||||||
|
|
||||||
private final static String irCacheDataExtension = ".ir";
|
private static final String irCacheDataExtension = ".ir";
|
||||||
|
|
||||||
private final static String irCacheMetadataExtension = ".meta";
|
private static final String irCacheMetadataExtension = ".meta";
|
||||||
|
|
||||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static <T extends Exception> T raise(Class<T> cls, Exception e) throws T {
|
private static <T extends Exception> T raise(Class<T> cls, Exception e) throws T {
|
||||||
throw (T)e;
|
throw (T) e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,24 +11,23 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.logging.Level;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.enso.editions.LibraryName;
|
import org.enso.editions.LibraryName;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.pkg.SourceFile;
|
import org.enso.pkg.SourceFile;
|
||||||
import org.enso.polyglot.Suggestion;
|
import org.enso.polyglot.Suggestion;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public final class SuggestionsCache
|
public final class SuggestionsCache
|
||||||
extends Cache<SuggestionsCache.CachedSuggestions, SuggestionsCache.Metadata> {
|
extends Cache<SuggestionsCache.CachedSuggestions, SuggestionsCache.Metadata> {
|
||||||
|
|
||||||
private static final String SUGGESTIONS_CACHE_DATA_EXTENSION = ".suggestions";
|
private static final String SUGGESTIONS_CACHE_DATA_EXTENSION = ".suggestions";
|
||||||
private static final String SUGGESTIONS_CACHE_METADATA_EXTENSION =".suggestions.meta";
|
private static final String SUGGESTIONS_CACHE_METADATA_EXTENSION = ".suggestions.meta";
|
||||||
|
|
||||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
final LibraryName libraryName;
|
final LibraryName libraryName;
|
||||||
|
|
||||||
@ -43,20 +42,24 @@ public final class SuggestionsCache
|
|||||||
@Override
|
@Override
|
||||||
protected byte[] metadata(String sourceDigest, String blobDigest, CachedSuggestions entry) {
|
protected byte[] metadata(String sourceDigest, String blobDigest, CachedSuggestions entry) {
|
||||||
try {
|
try {
|
||||||
return objectMapper.writeValueAsString(new Metadata(sourceDigest, blobDigest)).getBytes(metadataCharset);
|
return objectMapper
|
||||||
|
.writeValueAsString(new Metadata(sourceDigest, blobDigest))
|
||||||
|
.getBytes(metadataCharset);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CachedSuggestions deserialize(EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger)
|
protected CachedSuggestions deserialize(
|
||||||
throws ClassNotFoundException, ClassNotFoundException, IOException {
|
EnsoContext context, byte[] data, Metadata meta, TruffleLogger logger)
|
||||||
|
throws ClassNotFoundException, ClassNotFoundException, IOException {
|
||||||
try (var stream = new ObjectInputStream(new ByteArrayInputStream(data))) {
|
try (var stream = new ObjectInputStream(new ByteArrayInputStream(data))) {
|
||||||
if (stream.readObject() instanceof Suggestions suggestions) {
|
if (stream.readObject() instanceof Suggestions suggestions) {
|
||||||
return new CachedSuggestions(libraryName, suggestions, Optional.empty());
|
return new CachedSuggestions(libraryName, suggestions, Optional.empty());
|
||||||
} else {
|
} else {
|
||||||
throw new ClassNotFoundException("Expected SuggestionsCache.Suggestions, got " + data.getClass());
|
throw new ClassNotFoundException(
|
||||||
|
"Expected SuggestionsCache.Suggestions, got " + data.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,22 +90,29 @@ public final class SuggestionsCache
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Optional<Roots> getCacheRoots(EnsoContext context) {
|
protected Optional<Roots> getCacheRoots(EnsoContext context) {
|
||||||
return context.getPackageRepository().getPackageForLibraryJava(libraryName).map(pkg -> {
|
return context
|
||||||
var bindingsCacheRoot = pkg.getSuggestionsCacheRootForPackage(Info.ensoVersion());
|
.getPackageRepository()
|
||||||
var localCacheRoot = bindingsCacheRoot.resolve(libraryName.namespace());
|
.getPackageForLibraryJava(libraryName)
|
||||||
var distribution = context.getDistributionManager();
|
.map(
|
||||||
var pathSegments = new String[]{
|
pkg -> {
|
||||||
pkg.namespace(),
|
var bindingsCacheRoot = pkg.getSuggestionsCacheRootForPackage(Info.ensoVersion());
|
||||||
pkg.normalizedName(),
|
var localCacheRoot = bindingsCacheRoot.resolve(libraryName.namespace());
|
||||||
pkg.getConfig().version(),
|
var distribution = context.getDistributionManager();
|
||||||
Info.ensoVersion(),
|
var pathSegments =
|
||||||
libraryName.namespace()
|
new String[] {
|
||||||
};
|
pkg.namespace(),
|
||||||
var path = distribution.LocallyInstalledDirectories().irCacheDirectory()
|
pkg.normalizedName(),
|
||||||
.resolve(StringUtils.join(pathSegments, "/"));
|
pkg.getConfig().version(),
|
||||||
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
Info.ensoVersion(),
|
||||||
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
libraryName.namespace()
|
||||||
});
|
};
|
||||||
|
var path =
|
||||||
|
distribution.LocallyInstalledDirectories()
|
||||||
|
.irCacheDirectory()
|
||||||
|
.resolve(StringUtils.join(pathSegments, "/"));
|
||||||
|
var globalCacheRoot = context.getTruffleFile(path.toFile());
|
||||||
|
return new Cache.Roots(localCacheRoot, globalCacheRoot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -115,11 +125,11 @@ public final class SuggestionsCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Suggestions class is not a record because of a Frgaal bug leading to invalid compilation error.
|
// Suggestions class is not a record because of a Frgaal bug leading to invalid compilation error.
|
||||||
public final static class Suggestions implements Serializable {
|
public static final class Suggestions implements Serializable {
|
||||||
|
|
||||||
private final List<Suggestion> suggestions;
|
private final List<Suggestion> suggestions;
|
||||||
|
|
||||||
public Suggestions(List<Suggestion> suggestions) {
|
public Suggestions(List<Suggestion> suggestions) {
|
||||||
this.suggestions = suggestions;
|
this.suggestions = suggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,15 +138,19 @@ public final class SuggestionsCache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CachedSuggestions class is not a record because of a Frgaal bug leading to invalid compilation error.
|
// CachedSuggestions class is not a record because of a Frgaal bug leading to invalid compilation
|
||||||
public final static class CachedSuggestions {
|
// error.
|
||||||
|
public static final class CachedSuggestions {
|
||||||
|
|
||||||
private final LibraryName libraryName;
|
private final LibraryName libraryName;
|
||||||
private final Suggestions suggestions;
|
private final Suggestions suggestions;
|
||||||
|
|
||||||
private final Optional<List<SourceFile<TruffleFile>>> sources;
|
private final Optional<List<SourceFile<TruffleFile>>> sources;
|
||||||
|
|
||||||
public CachedSuggestions(LibraryName libraryName, Suggestions suggestions, Optional<List<SourceFile<TruffleFile>>> sources) {
|
public CachedSuggestions(
|
||||||
|
LibraryName libraryName,
|
||||||
|
Suggestions suggestions,
|
||||||
|
Optional<List<SourceFile<TruffleFile>>> sources) {
|
||||||
this.libraryName = libraryName;
|
this.libraryName = libraryName;
|
||||||
this.suggestions = suggestions;
|
this.suggestions = suggestions;
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
@ -160,7 +174,6 @@ public final class SuggestionsCache
|
|||||||
}
|
}
|
||||||
|
|
||||||
record Metadata(
|
record Metadata(
|
||||||
@JsonProperty("source_hash") String sourceHash,
|
@JsonProperty("source_hash") String sourceHash, @JsonProperty("blob_hash") String blobHash)
|
||||||
@JsonProperty("blob_hash") String blobHash
|
implements Cache.Metadata {}
|
||||||
) implements Cache.Metadata { }
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,9 @@ public abstract class BaseNode extends Node {
|
|||||||
this.tailStatus = tailStatus;
|
this.tailStatus = tailStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the tail position status of this node. */
|
/**
|
||||||
|
* @return the tail position status of this node.
|
||||||
|
*/
|
||||||
public TailStatus getTailStatus() {
|
public TailStatus getTailStatus() {
|
||||||
return tailStatus;
|
return tailStatus;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
package org.enso.interpreter.node;
|
package org.enso.interpreter.node;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
|
import com.oracle.truffle.api.frame.FrameSlotKind;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import org.enso.compiler.context.LocalScope;
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.compiler.context.LocalScope;
|
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
import org.enso.interpreter.util.ScalaConversions;
|
import org.enso.interpreter.util.ScalaConversions;
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
|
||||||
import com.oracle.truffle.api.frame.FrameSlotKind;
|
|
||||||
|
|
||||||
/** A common base class for all kinds of root node in Enso. */
|
/** A common base class for all kinds of root node in Enso. */
|
||||||
@NodeInfo(shortName = "Root", description = "A root node for Enso computations")
|
@NodeInfo(shortName = "Root", description = "A root node for Enso computations")
|
||||||
public abstract class EnsoRootNode extends RootNode {
|
public abstract class EnsoRootNode extends RootNode {
|
||||||
@ -47,7 +44,8 @@ public abstract class EnsoRootNode extends RootNode {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.localScope = localScope;
|
this.localScope = localScope;
|
||||||
this.moduleScope = moduleScope;
|
this.moduleScope = moduleScope;
|
||||||
if (sourceSection == null || moduleScope.getModule().isModuleSource(sourceSection.getSource())) {
|
if (sourceSection == null
|
||||||
|
|| moduleScope.getModule().isModuleSource(sourceSection.getSource())) {
|
||||||
this.inlineSource = null;
|
this.inlineSource = null;
|
||||||
} else {
|
} else {
|
||||||
this.inlineSource = sourceSection.getSource();
|
this.inlineSource = sourceSection.getSource();
|
||||||
@ -57,19 +55,16 @@ public abstract class EnsoRootNode extends RootNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a {@link FrameDescriptor} from the alias analysis scope metadata
|
* Builds a {@link FrameDescriptor} from the alias analysis scope metadata for the local scope.
|
||||||
* for the local scope. See [[AliasAnalysis.Graph.Scope.allDefinitions]].
|
* See [[AliasAnalysis.Graph.Scope.allDefinitions]].
|
||||||
*
|
*
|
||||||
* @return {@link FrameDescriptor} built from the variable definitions in
|
* @return {@link FrameDescriptor} built from the variable definitions in the local localScope.
|
||||||
* the local localScope.
|
|
||||||
*/
|
*/
|
||||||
private static FrameDescriptor buildFrameDescriptor(LocalScope localScope) {
|
private static FrameDescriptor buildFrameDescriptor(LocalScope localScope) {
|
||||||
var descriptorBuilder = FrameDescriptor.newBuilder();
|
var descriptorBuilder = FrameDescriptor.newBuilder();
|
||||||
descriptorBuilder.addSlot(FrameSlotKind.Object, LocalScope.monadicStateSlotName(), null);
|
descriptorBuilder.addSlot(FrameSlotKind.Object, LocalScope.monadicStateSlotName(), null);
|
||||||
for (var definition : ScalaConversions.asJava(localScope.scope().allDefinitions())) {
|
for (var definition : ScalaConversions.asJava(localScope.scope().allDefinitions())) {
|
||||||
descriptorBuilder.addSlot(
|
descriptorBuilder.addSlot(FrameSlotKind.Illegal, definition.symbol(), null);
|
||||||
FrameSlotKind.Illegal, definition.symbol(), null
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
descriptorBuilder.defaultValue(DataflowError.UNINITIALIZED);
|
descriptorBuilder.defaultValue(DataflowError.UNINITIALIZED);
|
||||||
var frameDescriptor = descriptorBuilder.build();
|
var frameDescriptor = descriptorBuilder.build();
|
||||||
@ -116,13 +111,17 @@ public abstract class EnsoRootNode extends RootNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final int NO_SOURCE = -1;
|
static final int NO_SOURCE = -1;
|
||||||
|
|
||||||
static SourceSection findSourceSection(final RootNode n, int sourceStartIndex, int sourceLength) {
|
static SourceSection findSourceSection(final RootNode n, int sourceStartIndex, int sourceLength) {
|
||||||
if (sourceStartIndex != NO_SOURCE && n instanceof EnsoRootNode rootNode) {
|
if (sourceStartIndex != NO_SOURCE && n instanceof EnsoRootNode rootNode) {
|
||||||
if (rootNode.inlineSource == null) {
|
if (rootNode.inlineSource == null) {
|
||||||
if (rootNode.sourceStartIndex == NO_SOURCE) {
|
if (rootNode.sourceStartIndex == NO_SOURCE) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return rootNode.getModuleScope().getModule().createSection(sourceStartIndex, sourceLength);
|
return rootNode
|
||||||
|
.getModuleScope()
|
||||||
|
.getModule()
|
||||||
|
.createSection(sourceStartIndex, sourceLength);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return rootNode.inlineSource.createSection(sourceStartIndex, sourceLength);
|
return rootNode.inlineSource.createSection(sourceStartIndex, sourceLength);
|
||||||
|
@ -5,12 +5,10 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
|||||||
import com.oracle.truffle.api.frame.Frame;
|
import com.oracle.truffle.api.frame.Frame;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.instrumentation.GenerateWrapper;
|
import com.oracle.truffle.api.instrumentation.GenerateWrapper;
|
||||||
import com.oracle.truffle.api.instrumentation.GenerateWrapper.OutgoingConverter;
|
|
||||||
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
|
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
|
||||||
import com.oracle.truffle.api.instrumentation.ProbeNode;
|
import com.oracle.truffle.api.instrumentation.ProbeNode;
|
||||||
import com.oracle.truffle.api.instrumentation.StandardTags;
|
import com.oracle.truffle.api.instrumentation.StandardTags;
|
||||||
import com.oracle.truffle.api.instrumentation.Tag;
|
import com.oracle.truffle.api.instrumentation.Tag;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.NodeLibrary;
|
import com.oracle.truffle.api.interop.NodeLibrary;
|
||||||
import com.oracle.truffle.api.library.ExportLibrary;
|
import com.oracle.truffle.api.library.ExportLibrary;
|
||||||
import com.oracle.truffle.api.library.ExportMessage;
|
import com.oracle.truffle.api.library.ExportMessage;
|
||||||
@ -18,9 +16,7 @@ import com.oracle.truffle.api.nodes.NodeInfo;
|
|||||||
import com.oracle.truffle.api.nodes.RootNode;
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import com.oracle.truffle.api.nodes.UnexpectedResultException;
|
import com.oracle.truffle.api.nodes.UnexpectedResultException;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.enso.interpreter.runtime.builtin.Builtins;
|
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
@ -52,9 +48,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
return node instanceof ExpressionNodeWrapper;
|
return node instanceof ExpressionNodeWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates a new instance of this node. */
|
||||||
* Creates a new instance of this node.
|
|
||||||
*/
|
|
||||||
public ExpressionNode() {
|
public ExpressionNode() {
|
||||||
sourceLength = EnsoRootNode.NO_SOURCE;
|
sourceLength = EnsoRootNode.NO_SOURCE;
|
||||||
sourceStartIndex = EnsoRootNode.NO_SOURCE;
|
sourceStartIndex = EnsoRootNode.NO_SOURCE;
|
||||||
@ -64,7 +58,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
* Sets the source location of this node.
|
* Sets the source location of this node.
|
||||||
*
|
*
|
||||||
* @param sourceStartIndex the source index this node begins at
|
* @param sourceStartIndex the source index this node begins at
|
||||||
* @param sourceLength the length of this node's source
|
* @param sourceLength the length of this node's source
|
||||||
*/
|
*/
|
||||||
public void setSourceLocation(int sourceStartIndex, int sourceLength) {
|
public void setSourceLocation(int sourceStartIndex, int sourceLength) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
@ -80,7 +74,9 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
@Override
|
@Override
|
||||||
public SourceSection getSourceSection() {
|
public SourceSection getSourceSection() {
|
||||||
var bounds = getSourceSectionBounds();
|
var bounds = getSourceSectionBounds();
|
||||||
return bounds == null ? null : EnsoRootNode.findSourceSection(getRootNode(), bounds[0], bounds[1]);
|
return bounds == null
|
||||||
|
? null
|
||||||
|
: EnsoRootNode.findSourceSection(getRootNode(), bounds[0], bounds[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] getSourceSectionBounds() {
|
public int[] getSourceSectionBounds() {
|
||||||
@ -90,7 +86,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
if (sourceStartIndex == EnsoRootNode.NO_SOURCE && sourceLength == EnsoRootNode.NO_SOURCE) {
|
if (sourceStartIndex == EnsoRootNode.NO_SOURCE && sourceLength == EnsoRootNode.NO_SOURCE) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return new int[] { sourceStartIndex, sourceLength };
|
return new int[] {sourceStartIndex, sourceLength};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +116,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
* @param frame the stack frame for execution
|
* @param frame the stack frame for execution
|
||||||
* @return the {@code long} value obtained by executing the node
|
* @return the {@code long} value obtained by executing the node
|
||||||
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
||||||
* type
|
* type
|
||||||
*/
|
*/
|
||||||
public long executeLong(VirtualFrame frame) throws UnexpectedResultException {
|
public long executeLong(VirtualFrame frame) throws UnexpectedResultException {
|
||||||
return TypesGen.expectLong(executeGeneric(frame));
|
return TypesGen.expectLong(executeGeneric(frame));
|
||||||
@ -132,7 +128,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
* @param frame the stack frame for execution
|
* @param frame the stack frame for execution
|
||||||
* @return the Atom constructor obtained by executing the node
|
* @return the Atom constructor obtained by executing the node
|
||||||
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
||||||
* type
|
* type
|
||||||
*/
|
*/
|
||||||
public AtomConstructor executeAtomConstructor(VirtualFrame frame)
|
public AtomConstructor executeAtomConstructor(VirtualFrame frame)
|
||||||
throws UnexpectedResultException {
|
throws UnexpectedResultException {
|
||||||
@ -145,7 +141,7 @@ public abstract class ExpressionNode extends BaseNode implements InstrumentableN
|
|||||||
* @param frame the stack frame for execution
|
* @param frame the stack frame for execution
|
||||||
* @return the function obtained by executing the node
|
* @return the function obtained by executing the node
|
||||||
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
* @throws UnexpectedResultException if the result cannot be represented as a value of the return
|
||||||
* type
|
* type
|
||||||
*/
|
*/
|
||||||
public Function executeFunction(VirtualFrame frame) throws UnexpectedResultException {
|
public Function executeFunction(VirtualFrame frame) throws UnexpectedResultException {
|
||||||
return TypesGen.expectFunction(executeGeneric(frame));
|
return TypesGen.expectFunction(executeGeneric(frame));
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
package org.enso.interpreter.node;
|
package org.enso.interpreter.node;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.enso.compiler.core.CompilerError;
|
|
||||||
import org.enso.compiler.context.LocalScope;
|
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.dsl.ReportPolymorphism;
|
import com.oracle.truffle.api.dsl.ReportPolymorphism;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import org.enso.compiler.context.LocalScope;
|
||||||
|
import org.enso.compiler.core.CompilerError;
|
||||||
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
|
|
||||||
@ReportPolymorphism
|
@ReportPolymorphism
|
||||||
@NodeInfo(shortName = "Method", description = "A root node for Enso methods.")
|
@NodeInfo(shortName = "Method", description = "A root node for Enso methods.")
|
||||||
@ -33,12 +31,15 @@ public class MethodRootNode extends ClosureRootNode {
|
|||||||
SourceSection section,
|
SourceSection section,
|
||||||
Type type,
|
Type type,
|
||||||
String methodName) {
|
String methodName) {
|
||||||
super(language,
|
super(
|
||||||
|
language,
|
||||||
localScope,
|
localScope,
|
||||||
moduleScope,
|
moduleScope,
|
||||||
body,
|
body,
|
||||||
section,
|
section,
|
||||||
shortName(type.getName(), methodName), null, false);
|
shortName(type.getName(), methodName),
|
||||||
|
null,
|
||||||
|
false);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
}
|
}
|
||||||
@ -68,13 +69,7 @@ public class MethodRootNode extends ClosureRootNode {
|
|||||||
Type type,
|
Type type,
|
||||||
String methodName) {
|
String methodName) {
|
||||||
return build(
|
return build(
|
||||||
language,
|
language, localScope, moduleScope, new LazyBodyNode(body), section, type, methodName);
|
||||||
localScope,
|
|
||||||
moduleScope,
|
|
||||||
new LazyBodyNode(body),
|
|
||||||
section,
|
|
||||||
type,
|
|
||||||
methodName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodRootNode build(
|
public static MethodRootNode build(
|
||||||
@ -85,8 +80,7 @@ public class MethodRootNode extends ClosureRootNode {
|
|||||||
SourceSection section,
|
SourceSection section,
|
||||||
Type type,
|
Type type,
|
||||||
String methodName) {
|
String methodName) {
|
||||||
return new MethodRootNode(
|
return new MethodRootNode(language, localScope, moduleScope, body, section, type, methodName);
|
||||||
language, localScope, moduleScope, body, section, type, methodName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,12 +99,16 @@ public class MethodRootNode extends ClosureRootNode {
|
|||||||
+ methodName;
|
+ methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the constructor this method was defined for */
|
/**
|
||||||
|
* @return the constructor this method was defined for
|
||||||
|
*/
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the method name */
|
/**
|
||||||
|
* @return the method name
|
||||||
|
*/
|
||||||
public String getMethodName() {
|
public String getMethodName() {
|
||||||
return methodName;
|
return methodName;
|
||||||
}
|
}
|
||||||
@ -160,6 +158,7 @@ public class MethodRootNode extends ClosureRootNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSubjectToInstrumentation() {
|
public boolean isSubjectToInstrumentation() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,17 @@ import com.oracle.truffle.api.nodes.DirectCallNode;
|
|||||||
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
|
import org.enso.interpreter.node.InlineableNode;
|
||||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.node.InlineableNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This node is responsible for optimising function calls. Where possible, it will handle the call via:
|
* This node is responsible for optimising function calls. Where possible, it will handle the call
|
||||||
|
* via:
|
||||||
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link InlineableNode} to force inlining</li>
|
* <li>{@link InlineableNode} to force inlining
|
||||||
* <li>{@link DirectCallNode} with potential for inlining</li>
|
* <li>{@link DirectCallNode} with potential for inlining
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@NodeInfo(shortName = "ExecCall", description = "Optimises function calls")
|
@NodeInfo(shortName = "ExecCall", description = "Optimises function calls")
|
||||||
@ -47,10 +49,9 @@ public abstract class ExecuteCallNode extends Node {
|
|||||||
* @param callNode the cached call node for {@code cachedTarget}
|
* @param callNode the cached call node for {@code cachedTarget}
|
||||||
* @return the result of executing {@code function} on {@code arguments}
|
* @return the result of executing {@code function} on {@code arguments}
|
||||||
*/
|
*/
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"function.getCallTarget() == cachedTarget",
|
guards = {"function.getCallTarget() == cachedTarget", "callNode != null"},
|
||||||
"callNode != null"
|
limit = "3")
|
||||||
}, limit = "3")
|
|
||||||
protected Object callInlineable(
|
protected Object callInlineable(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
Function function,
|
Function function,
|
||||||
@ -77,9 +78,11 @@ public abstract class ExecuteCallNode extends Node {
|
|||||||
* @param callNode the cached call node for {@code cachedTarget}
|
* @param callNode the cached call node for {@code cachedTarget}
|
||||||
* @return the result of executing {@code function} on {@code arguments}
|
* @return the result of executing {@code function} on {@code arguments}
|
||||||
*/
|
*/
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"function.getCallTarget() == cachedTarget",
|
guards = {
|
||||||
}, limit = "3")
|
"function.getCallTarget() == cachedTarget",
|
||||||
|
},
|
||||||
|
limit = "3")
|
||||||
protected Object callDirect(
|
protected Object callDirect(
|
||||||
Function function,
|
Function function,
|
||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
@ -115,7 +118,7 @@ public abstract class ExecuteCallNode extends Node {
|
|||||||
* @param callNode the cached call node for making indirect calls
|
* @param callNode the cached call node for making indirect calls
|
||||||
* @return the result of executing {@code function} on {@code arguments}
|
* @return the result of executing {@code function} on {@code arguments}
|
||||||
*/
|
*/
|
||||||
@Specialization(replaces = { "callDirect", "callInlineable" })
|
@Specialization(replaces = {"callDirect", "callInlineable"})
|
||||||
protected Object callIndirect(
|
protected Object callIndirect(
|
||||||
Function function,
|
Function function,
|
||||||
CallerInfo callerInfo,
|
CallerInfo callerInfo,
|
||||||
@ -138,5 +141,9 @@ public abstract class ExecuteCallNode extends Node {
|
|||||||
* @return the result of executing {@code function} on {@code arguments}
|
* @return the result of executing {@code function} on {@code arguments}
|
||||||
*/
|
*/
|
||||||
public abstract Object executeCall(
|
public abstract Object executeCall(
|
||||||
VirtualFrame frame, Function function, CallerInfo callerInfo, Object state, Object[] arguments);
|
VirtualFrame frame,
|
||||||
|
Function function,
|
||||||
|
CallerInfo callerInfo,
|
||||||
|
Object state,
|
||||||
|
Object[] arguments);
|
||||||
}
|
}
|
||||||
|
@ -10,22 +10,18 @@ import com.oracle.truffle.api.instrumentation.ProbeNode;
|
|||||||
import com.oracle.truffle.api.instrumentation.StandardTags;
|
import com.oracle.truffle.api.instrumentation.StandardTags;
|
||||||
import com.oracle.truffle.api.instrumentation.Tag;
|
import com.oracle.truffle.api.instrumentation.Tag;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
import com.oracle.truffle.api.interop.TruffleObject;
|
|
||||||
import com.oracle.truffle.api.library.ExportLibrary;
|
import com.oracle.truffle.api.library.ExportLibrary;
|
||||||
import com.oracle.truffle.api.library.ExportMessage;
|
import com.oracle.truffle.api.library.ExportMessage;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
|
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
|
||||||
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.enso.interpreter.node.ClosureRootNode;
|
import org.enso.interpreter.node.ClosureRootNode;
|
||||||
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
import org.enso.interpreter.runtime.tag.AvoidIdInstrumentationTag;
|
||||||
|
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node used for instrumenting function calls. It does nothing useful from the language
|
* A node used for instrumenting function calls. It does nothing useful from the language
|
||||||
@ -108,17 +104,23 @@ public class FunctionCallInstrumentationNode extends Node implements Instrumenta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the function for this call. */
|
/**
|
||||||
|
* @return the function for this call.
|
||||||
|
*/
|
||||||
public Function getFunction() {
|
public Function getFunction() {
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the state passed to the function in this call. */
|
/**
|
||||||
|
* @return the state passed to the function in this call.
|
||||||
|
*/
|
||||||
public Object getState() {
|
public Object getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the arguments passed to the function in this call. */
|
/**
|
||||||
|
* @return the arguments passed to the function in this call.
|
||||||
|
*/
|
||||||
public Object[] getArguments() {
|
public Object[] getArguments() {
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
@ -126,7 +128,11 @@ public class FunctionCallInstrumentationNode extends Node implements Instrumenta
|
|||||||
@Override
|
@Override
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "FunctionCall[function=" + function + ", arguments: " + Arrays.toString(arguments) + "]";
|
return "FunctionCall[function="
|
||||||
|
+ function
|
||||||
|
+ ", arguments: "
|
||||||
|
+ Arrays.toString(arguments)
|
||||||
|
+ "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +176,9 @@ public class FunctionCallInstrumentationNode extends Node implements Instrumenta
|
|||||||
return tag == StandardTags.CallTag.class || (tag == IdentifiedTag.class && id != null);
|
return tag == StandardTags.CallTag.class || (tag == IdentifiedTag.class && id != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the source section of this node. */
|
/**
|
||||||
|
* @return the source section of this node.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SourceSection getSourceSection() {
|
public SourceSection getSourceSection() {
|
||||||
var parent = getParent();
|
var parent = getParent();
|
||||||
@ -184,7 +192,9 @@ public class FunctionCallInstrumentationNode extends Node implements Instrumenta
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the expression ID of this node. */
|
/**
|
||||||
|
* @return the expression ID of this node.
|
||||||
|
*/
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
|||||||
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
||||||
public abstract class IndirectInvokeConversionNode extends Node {
|
public abstract class IndirectInvokeConversionNode extends Node {
|
||||||
|
|
||||||
/** @return a new indirect method invocation node */
|
/**
|
||||||
|
* @return a new indirect method invocation node
|
||||||
|
*/
|
||||||
public static IndirectInvokeConversionNode build() {
|
public static IndirectInvokeConversionNode build() {
|
||||||
return IndirectInvokeConversionNodeGen.create();
|
return IndirectInvokeConversionNodeGen.create();
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,9 @@ import org.enso.interpreter.runtime.state.State;
|
|||||||
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
||||||
public abstract class IndirectInvokeMethodNode extends Node {
|
public abstract class IndirectInvokeMethodNode extends Node {
|
||||||
|
|
||||||
/** @return a new indirect method invocation node */
|
/**
|
||||||
|
* @return a new indirect method invocation node
|
||||||
|
*/
|
||||||
public static IndirectInvokeMethodNode build() {
|
public static IndirectInvokeMethodNode build() {
|
||||||
return IndirectInvokeMethodNodeGen.create();
|
return IndirectInvokeMethodNodeGen.create();
|
||||||
}
|
}
|
||||||
|
@ -215,8 +215,10 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selfArgument = thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL);
|
selfArgument =
|
||||||
thatArgument = thatExecutor.executeThunk(callerFrame, thatArgument, state, TailStatus.NOT_TAIL);
|
thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL);
|
||||||
|
thatArgument =
|
||||||
|
thatExecutor.executeThunk(callerFrame, thatArgument, state, TailStatus.NOT_TAIL);
|
||||||
|
|
||||||
arguments[thisArgumentPosition] = selfArgument;
|
arguments[thisArgumentPosition] = selfArgument;
|
||||||
arguments[thatArgumentPosition] = thatArgument;
|
arguments[thatArgumentPosition] = thatArgument;
|
||||||
@ -226,7 +228,11 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
} else {
|
} else {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
throw new PanicException(ctx.getBuiltins().error().makeNoConversionCurrying(canApplyThis, canApplyThat, conversion), this);
|
throw new PanicException(
|
||||||
|
ctx.getBuiltins()
|
||||||
|
.error()
|
||||||
|
.makeNoConversionCurrying(canApplyThis, canApplyThat, conversion),
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +254,8 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selfArgument = thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL);
|
selfArgument =
|
||||||
|
thisExecutor.executeThunk(callerFrame, selfArgument, state, TailStatus.NOT_TAIL);
|
||||||
arguments[thisArgumentPosition] = selfArgument;
|
arguments[thisArgumentPosition] = selfArgument;
|
||||||
}
|
}
|
||||||
return invokeMethodNode.execute(callerFrame, state, symbol, selfArgument, arguments);
|
return invokeMethodNode.execute(callerFrame, state, symbol, selfArgument, arguments);
|
||||||
@ -282,11 +289,11 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
try {
|
try {
|
||||||
if (childDispatch == null) {
|
if (childDispatch == null) {
|
||||||
childDispatch =
|
childDispatch =
|
||||||
insert(
|
insert(
|
||||||
build(
|
build(
|
||||||
invokeFunctionNode.getSchema(),
|
invokeFunctionNode.getSchema(),
|
||||||
invokeFunctionNode.getDefaultsExecutionMode(),
|
invokeFunctionNode.getDefaultsExecutionMode(),
|
||||||
invokeFunctionNode.getArgumentsExecutionMode()));
|
invokeFunctionNode.getArgumentsExecutionMode()));
|
||||||
childDispatch.setTailStatus(getTailStatus());
|
childDispatch.setTailStatus(getTailStatus());
|
||||||
childDispatch.setId(invokeFunctionNode.getId());
|
childDispatch.setId(invokeFunctionNode.getId());
|
||||||
notifyInserted(childDispatch);
|
notifyInserted(childDispatch);
|
||||||
@ -296,12 +303,7 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = childDispatch.execute(
|
var result = childDispatch.execute(callable, callerFrame, state, arguments);
|
||||||
callable,
|
|
||||||
callerFrame,
|
|
||||||
state,
|
|
||||||
arguments);
|
|
||||||
|
|
||||||
|
|
||||||
if (result instanceof DataflowError) {
|
if (result instanceof DataflowError) {
|
||||||
return result;
|
return result;
|
||||||
@ -350,7 +352,9 @@ public abstract class InvokeCallableNode extends BaseNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the source section for this node. */
|
/**
|
||||||
|
* @return the source section for this node.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SourceSection getSourceSection() {
|
public SourceSection getSourceSection() {
|
||||||
Node parent = getParent();
|
Node parent = getParent();
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
package org.enso.interpreter.node.callable;
|
package org.enso.interpreter.node.callable;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
import org.enso.interpreter.node.BaseNode;
|
import org.enso.interpreter.node.BaseNode;
|
||||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||||
import org.enso.interpreter.node.callable.resolver.ConversionResolverNode;
|
import org.enso.interpreter.node.callable.resolver.ConversionResolverNode;
|
||||||
@ -23,17 +32,6 @@ import org.enso.interpreter.runtime.error.WithWarnings;
|
|||||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
|
||||||
|
|
||||||
public abstract class InvokeConversionNode extends BaseNode {
|
public abstract class InvokeConversionNode extends BaseNode {
|
||||||
private @Child InvokeFunctionNode invokeFunctionNode;
|
private @Child InvokeFunctionNode invokeFunctionNode;
|
||||||
private @Child InvokeConversionNode childDispatch;
|
private @Child InvokeConversionNode childDispatch;
|
||||||
@ -132,9 +130,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary dispatch,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary dispatch,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.execute(extractType(self),
|
conversionResolverNode.execute(
|
||||||
EnsoContext.get(this).getBuiltins().dataflowError(),
|
extractType(self), EnsoContext.get(this).getBuiltins().dataflowError(), conversion);
|
||||||
conversion);
|
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
} else {
|
} else {
|
||||||
@ -165,10 +162,7 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
var result = that.castTo(type);
|
var result = that.castTo(type);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new PanicException(
|
throw new PanicException(
|
||||||
EnsoContext.get(this)
|
EnsoContext.get(this).getBuiltins().error().makeNoSuchConversion(type, self, conversion),
|
||||||
.getBuiltins()
|
|
||||||
.error()
|
|
||||||
.makeNoSuchConversion(type, self, conversion),
|
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -229,10 +223,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
String str = interop.asString(that);
|
String str = interop.asString(that);
|
||||||
Text txt = Text.create(str);
|
Text txt = Text.create(str);
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(txt,
|
conversionResolverNode.expectNonNull(
|
||||||
extractType(self),
|
txt, extractType(self), EnsoContext.get(this).getBuiltins().text(), conversion);
|
||||||
EnsoContext.get(this).getBuiltins().text(),
|
|
||||||
conversion);
|
|
||||||
arguments[0] = txt;
|
arguments[0] = txt;
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
@ -258,7 +250,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(that, extractType(self), EnsoContext.get(this).getBuiltins().date(), conversion);
|
conversionResolverNode.expectNonNull(
|
||||||
|
that, extractType(self), EnsoContext.get(this).getBuiltins().date(), conversion);
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,10 +273,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(that,
|
conversionResolverNode.expectNonNull(
|
||||||
extractType(self),
|
that, extractType(self), EnsoContext.get(this).getBuiltins().timeOfDay(), conversion);
|
||||||
EnsoContext.get(this).getBuiltins().timeOfDay(),
|
|
||||||
conversion);
|
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,10 +296,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(that,
|
conversionResolverNode.expectNonNull(
|
||||||
extractType(self),
|
that, extractType(self), EnsoContext.get(this).getBuiltins().dateTime(), conversion);
|
||||||
EnsoContext.get(this).getBuiltins().dateTime(),
|
|
||||||
conversion);
|
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,10 +318,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(that,
|
conversionResolverNode.expectNonNull(
|
||||||
extractType(self),
|
that, extractType(self), EnsoContext.get(this).getBuiltins().duration(), conversion);
|
||||||
EnsoContext.get(this).getBuiltins().duration(),
|
|
||||||
conversion);
|
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,10 +340,8 @@ public abstract class InvokeConversionNode extends BaseNode {
|
|||||||
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
@Shared("typesLib") @CachedLibrary(limit = "10") TypesLibrary typesLib,
|
||||||
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
@Shared("conversionResolverNode") @Cached ConversionResolverNode conversionResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
conversionResolverNode.expectNonNull(thatMap,
|
conversionResolverNode.expectNonNull(
|
||||||
extractType(self),
|
thatMap, extractType(self), EnsoContext.get(this).getBuiltins().map(), conversion);
|
||||||
EnsoContext.get(this).getBuiltins().map(),
|
|
||||||
conversion);
|
|
||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
package org.enso.interpreter.node.callable;
|
package org.enso.interpreter.node.callable;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.dsl.Bind;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
|
import com.oracle.truffle.api.dsl.ImportStatic;
|
||||||
|
import com.oracle.truffle.api.dsl.NonIdempotent;
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
|
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||||
|
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||||
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
@ -8,7 +26,6 @@ import java.util.Arrays;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
import org.enso.interpreter.Constants.Names;
|
import org.enso.interpreter.Constants.Names;
|
||||||
import org.enso.interpreter.node.BaseNode;
|
import org.enso.interpreter.node.BaseNode;
|
||||||
import org.enso.interpreter.node.MethodRootNode;
|
import org.enso.interpreter.node.MethodRootNode;
|
||||||
@ -44,29 +61,11 @@ import org.enso.interpreter.runtime.error.WithWarnings;
|
|||||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.dsl.Bind;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
|
||||||
import com.oracle.truffle.api.dsl.ImportStatic;
|
|
||||||
import com.oracle.truffle.api.dsl.NonIdempotent;
|
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
|
||||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
|
||||||
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
|
||||||
|
|
||||||
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
@ImportStatic({HostMethodCallNode.PolyglotCallType.class, HostMethodCallNode.class})
|
||||||
public abstract class InvokeMethodNode extends BaseNode {
|
public abstract class InvokeMethodNode extends BaseNode {
|
||||||
protected static final int CACHE_SIZE = 10;
|
protected static final int CACHE_SIZE = 10;
|
||||||
private @Child InvokeFunctionNode invokeFunctionNode;
|
private @Child InvokeFunctionNode invokeFunctionNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A node that is created specifically for cases when a static method is called on {@code Any}. In
|
* A node that is created specifically for cases when a static method is called on {@code Any}. In
|
||||||
* such cases, we need to modify the number of passed arguments, therefore, a new {@link
|
* such cases, we need to modify the number of passed arguments, therefore, a new {@link
|
||||||
@ -88,14 +87,16 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
* @param defaultsExecutionMode the defaulted arguments handling mode for this call
|
* @param defaultsExecutionMode the defaulted arguments handling mode for this call
|
||||||
* @param argumentsExecutionMode the arguments execution mode for this call
|
* @param argumentsExecutionMode the arguments execution mode for this call
|
||||||
* @param thisArgumentPosition position
|
* @param thisArgumentPosition position
|
||||||
* @param onBoundary shall we emit plain {@code PanicException} or also attach {@code UnknownIdentifierException} cause
|
* @param onBoundary shall we emit plain {@code PanicException} or also attach {@code
|
||||||
|
* UnknownIdentifierException} cause
|
||||||
* @return a new invoke method node
|
* @return a new invoke method node
|
||||||
*/
|
*/
|
||||||
public static InvokeMethodNode build(
|
public static InvokeMethodNode build(
|
||||||
CallArgumentInfo[] schema,
|
CallArgumentInfo[] schema,
|
||||||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode,
|
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode,
|
||||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||||
int thisArgumentPosition, boolean onBoundary) {
|
int thisArgumentPosition,
|
||||||
|
boolean onBoundary) {
|
||||||
return InvokeMethodNodeGen.create(
|
return InvokeMethodNodeGen.create(
|
||||||
schema, defaultsExecutionMode, argumentsExecutionMode, thisArgumentPosition, onBoundary);
|
schema, defaultsExecutionMode, argumentsExecutionMode, thisArgumentPosition, onBoundary);
|
||||||
}
|
}
|
||||||
@ -104,8 +105,8 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
CallArgumentInfo[] schema,
|
CallArgumentInfo[] schema,
|
||||||
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode,
|
InvokeCallableNode.DefaultsExecutionMode defaultsExecutionMode,
|
||||||
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
InvokeCallableNode.ArgumentsExecutionMode argumentsExecutionMode,
|
||||||
int thisArgumentPosition, boolean onBoundary
|
int thisArgumentPosition,
|
||||||
) {
|
boolean onBoundary) {
|
||||||
this.invokeFunctionNode =
|
this.invokeFunctionNode =
|
||||||
InvokeFunctionNode.build(schema, defaultsExecutionMode, argumentsExecutionMode);
|
InvokeFunctionNode.build(schema, defaultsExecutionMode, argumentsExecutionMode);
|
||||||
this.argumentCount = schema.length;
|
this.argumentCount = schema.length;
|
||||||
@ -219,17 +220,20 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
argsWithDefaultValCount++;
|
argsWithDefaultValCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Static method calls on Any are resolved to `Any.type.method`. Such methods take one additional
|
// Static method calls on Any are resolved to `Any.type.method`. Such methods take one
|
||||||
|
// additional
|
||||||
// self argument (with Any.type) as opposed to static method calls resolved on any other
|
// self argument (with Any.type) as opposed to static method calls resolved on any other
|
||||||
// types. This case is handled in the following block.
|
// types. This case is handled in the following block.
|
||||||
boolean shouldPrependSyntheticSelfArg = resolvedFuncArgCount - argsWithDefaultValCount == arguments.length + 1;
|
boolean shouldPrependSyntheticSelfArg =
|
||||||
|
resolvedFuncArgCount - argsWithDefaultValCount == arguments.length + 1;
|
||||||
if (isAnyEigenType(selfTpe) && shouldPrependSyntheticSelfArg) {
|
if (isAnyEigenType(selfTpe) && shouldPrependSyntheticSelfArg) {
|
||||||
// function is a static method on Any, so the first two arguments in `invokeFuncSchema`
|
// function is a static method on Any, so the first two arguments in `invokeFuncSchema`
|
||||||
// represent self arguments.
|
// represent self arguments.
|
||||||
boolean selfArgSpecified = false;
|
boolean selfArgSpecified = false;
|
||||||
if (invokeFuncSchema.length > 1) {
|
if (invokeFuncSchema.length > 1) {
|
||||||
selfArgSpecified =
|
selfArgSpecified =
|
||||||
invokeFuncSchema[1].getName() != null && invokeFuncSchema[1].getName().equals(Names.SELF_ARGUMENT);
|
invokeFuncSchema[1].getName() != null
|
||||||
|
&& invokeFuncSchema[1].getName().equals(Names.SELF_ARGUMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selfArgSpecified) {
|
if (selfArgSpecified) {
|
||||||
@ -270,7 +274,8 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
return invokeFunctionNode.execute(function, frame, state, arguments);
|
return invokeFunctionNode.execute(function, frame, state, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PanicException methodNotFound(UnresolvedSymbol symbol, Object self) throws PanicException {
|
private PanicException methodNotFound(UnresolvedSymbol symbol, Object self)
|
||||||
|
throws PanicException {
|
||||||
var cause = onBoundary ? UnknownIdentifierException.create(symbol.getName()) : null;
|
var cause = onBoundary ? UnknownIdentifierException.create(symbol.getName()) : null;
|
||||||
var payload = EnsoContext.get(this).getBuiltins().error().makeNoSuchMethod(self, symbol);
|
var payload = EnsoContext.get(this).getBuiltins().error().makeNoSuchMethod(self, symbol);
|
||||||
throw new PanicException(payload, cause, this);
|
throw new PanicException(payload, cause, this);
|
||||||
@ -283,8 +288,7 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
UnresolvedSymbol symbol,
|
UnresolvedSymbol symbol,
|
||||||
EnsoMultiValue self,
|
EnsoMultiValue self,
|
||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
@Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode
|
@Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) {
|
||||||
) {
|
|
||||||
var fnAndType = self.resolveSymbol(methodResolverNode, symbol);
|
var fnAndType = self.resolveSymbol(methodResolverNode, symbol);
|
||||||
if (fnAndType != null) {
|
if (fnAndType != null) {
|
||||||
var unwrapSelf = self.castTo(fnAndType.getRight());
|
var unwrapSelf = self.castTo(fnAndType.getRight());
|
||||||
@ -306,7 +310,8 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
Object[] arguments,
|
Object[] arguments,
|
||||||
@Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) {
|
@Shared("methodResolverNode") @Cached MethodResolverNode methodResolverNode) {
|
||||||
Function function =
|
Function function =
|
||||||
methodResolverNode.executeResolution(EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
|
methodResolverNode.executeResolution(
|
||||||
|
EnsoContext.get(this).getBuiltins().dataflowError(), symbol);
|
||||||
if (errorReceiverProfile.profile(function == null)) {
|
if (errorReceiverProfile.profile(function == null)) {
|
||||||
return self;
|
return self;
|
||||||
} else {
|
} else {
|
||||||
@ -444,7 +449,8 @@ public abstract class InvokeMethodNode extends BaseNode {
|
|||||||
invokeFunctionNode.getSchema(),
|
invokeFunctionNode.getSchema(),
|
||||||
invokeFunctionNode.getDefaultsExecutionMode(),
|
invokeFunctionNode.getDefaultsExecutionMode(),
|
||||||
invokeFunctionNode.getArgumentsExecutionMode(),
|
invokeFunctionNode.getArgumentsExecutionMode(),
|
||||||
thisArgumentPosition, false));
|
thisArgumentPosition,
|
||||||
|
false));
|
||||||
childDispatch.setTailStatus(getTailStatus());
|
childDispatch.setTailStatus(getTailStatus());
|
||||||
childDispatch.setId(invokeFunctionNode.getId());
|
childDispatch.setId(invokeFunctionNode.getId());
|
||||||
notifyInserted(childDispatch);
|
notifyInserted(childDispatch);
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package org.enso.interpreter.node.callable;
|
package org.enso.interpreter.node.callable;
|
||||||
|
|
||||||
import org.enso.interpreter.node.ExpressionNode;
|
|
||||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
|
||||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
|
import org.enso.interpreter.node.ExpressionNode;
|
||||||
|
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||||
|
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||||
|
|
||||||
@NodeInfo(shortName = "[]", description = "Creates a vector from given expressions.")
|
@NodeInfo(shortName = "[]", description = "Creates a vector from given expressions.")
|
||||||
public class SequenceLiteralNode extends ExpressionNode {
|
public class SequenceLiteralNode extends ExpressionNode {
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
package org.enso.interpreter.node.callable.argument;
|
package org.enso.interpreter.node.callable.argument;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerAsserts;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.TruffleLanguage;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
|
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.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
|
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.nodes.NodeUtil;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.enso.compiler.core.ir.Name;
|
import org.enso.compiler.core.ir.Name;
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
import org.enso.interpreter.node.BaseNode.TailStatus;
|
import org.enso.interpreter.node.BaseNode.TailStatus;
|
||||||
@ -34,42 +48,26 @@ import org.enso.interpreter.runtime.error.PanicSentinel;
|
|||||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||||
import org.graalvm.collections.Pair;
|
import org.graalvm.collections.Pair;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerAsserts;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.TruffleLanguage;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
|
||||||
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.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.nodes.NodeUtil;
|
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
|
||||||
|
|
||||||
public abstract class ReadArgumentCheckNode extends Node {
|
public abstract class ReadArgumentCheckNode extends Node {
|
||||||
private final String name;
|
private final String name;
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private String expectedTypeMessage;
|
||||||
private String expectedTypeMessage;
|
|
||||||
|
|
||||||
ReadArgumentCheckNode(String name) {
|
ReadArgumentCheckNode(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** */
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static ExpressionNode wrap(ExpressionNode original, ReadArgumentCheckNode check) {
|
public static ExpressionNode wrap(ExpressionNode original, ReadArgumentCheckNode check) {
|
||||||
return new TypeCheckExpressionNode(original, check);
|
return new TypeCheckExpressionNode(original, check);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Executes check or conversion of the value.abstract
|
/**
|
||||||
|
* Executes check or conversion of the value.abstract
|
||||||
|
*
|
||||||
* @param frame frame requesting the conversion
|
* @param frame frame requesting the conversion
|
||||||
* @param value the value to convert
|
* @param value the value to convert
|
||||||
* @return {@code null} when the check isn't satisfied and conversion isn't possible or non-{@code null} value that can be used as a result
|
* @return {@code null} when the check isn't satisfied and conversion isn't possible or non-{@code
|
||||||
|
* null} value that can be used as a result
|
||||||
*/
|
*/
|
||||||
public final Object handleCheckOrConversion(VirtualFrame frame, Object value) {
|
public final Object handleCheckOrConversion(VirtualFrame frame, Object value) {
|
||||||
var result = executeCheckOrConversion(frame, value);
|
var result = executeCheckOrConversion(frame, value);
|
||||||
@ -80,7 +78,9 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract Object findDirectMatch(VirtualFrame frame, Object value);
|
abstract Object findDirectMatch(VirtualFrame frame, Object value);
|
||||||
|
|
||||||
abstract Object executeCheckOrConversion(VirtualFrame frame, Object value);
|
abstract Object executeCheckOrConversion(VirtualFrame frame, Object value);
|
||||||
|
|
||||||
abstract String expectedTypeMessage();
|
abstract String expectedTypeMessage();
|
||||||
|
|
||||||
final PanicException panicAtTheEnd(Object v) {
|
final PanicException panicAtTheEnd(Object v) {
|
||||||
@ -96,7 +96,11 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
|
|
||||||
public static ReadArgumentCheckNode allOf(Name argumentName, ReadArgumentCheckNode... checks) {
|
public static ReadArgumentCheckNode allOf(Name argumentName, ReadArgumentCheckNode... checks) {
|
||||||
var list = Arrays.asList(checks);
|
var list = Arrays.asList(checks);
|
||||||
var flatten = list.stream().flatMap(n -> n instanceof AllOfNode all ? Arrays.asList(all.checks).stream() : Stream.of(n)).toList();
|
var flatten =
|
||||||
|
list.stream()
|
||||||
|
.flatMap(
|
||||||
|
n -> n instanceof AllOfNode all ? Arrays.asList(all.checks).stream() : Stream.of(n))
|
||||||
|
.toList();
|
||||||
var arr = toArray(flatten);
|
var arr = toArray(flatten);
|
||||||
return switch (arr.length) {
|
return switch (arr.length) {
|
||||||
case 0 -> null;
|
case 0 -> null;
|
||||||
@ -142,7 +146,7 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
var cnt = (int) list.stream().filter(n -> n != null).count();
|
var cnt = (int) list.stream().filter(n -> n != null).count();
|
||||||
var arr = new ReadArgumentCheckNode[cnt];
|
var arr = new ReadArgumentCheckNode[cnt];
|
||||||
var it = list.iterator();
|
var it = list.iterator();
|
||||||
for (int i = 0; i < cnt;) {
|
for (int i = 0; i < cnt; ) {
|
||||||
var element = it.next();
|
var element = it.next();
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
arr[i++] = element;
|
arr[i++] = element;
|
||||||
@ -152,10 +156,8 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final class AllOfNode extends ReadArgumentCheckNode {
|
static final class AllOfNode extends ReadArgumentCheckNode {
|
||||||
@Children
|
@Children private ReadArgumentCheckNode[] checks;
|
||||||
private ReadArgumentCheckNode[] checks;
|
@Child private TypesLibrary types;
|
||||||
@Child
|
|
||||||
private TypesLibrary types;
|
|
||||||
|
|
||||||
AllOfNode(String name, ReadArgumentCheckNode[] checks) {
|
AllOfNode(String name, ReadArgumentCheckNode[] checks) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -188,13 +190,14 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedTypeMessage() {
|
String expectedTypeMessage() {
|
||||||
return Arrays.stream(checks).map(n -> n.expectedTypeMessage()).collect(Collectors.joining(" & "));
|
return Arrays.stream(checks)
|
||||||
|
.map(n -> n.expectedTypeMessage())
|
||||||
|
.collect(Collectors.joining(" & "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class OneOfNode extends ReadArgumentCheckNode {
|
static final class OneOfNode extends ReadArgumentCheckNode {
|
||||||
@Children
|
@Children private ReadArgumentCheckNode[] checks;
|
||||||
private ReadArgumentCheckNode[] checks;
|
|
||||||
|
|
||||||
OneOfNode(String name, ReadArgumentCheckNode[] checks) {
|
OneOfNode(String name, ReadArgumentCheckNode[] checks) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -231,18 +234,17 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedTypeMessage() {
|
String expectedTypeMessage() {
|
||||||
return Arrays.stream(checks).map(n -> n.expectedTypeMessage()).collect(Collectors.joining(" | "));
|
return Arrays.stream(checks)
|
||||||
|
.map(n -> n.expectedTypeMessage())
|
||||||
|
.collect(Collectors.joining(" | "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class TypeCheckNode extends ReadArgumentCheckNode {
|
abstract static class TypeCheckNode extends ReadArgumentCheckNode {
|
||||||
private final Type expectedType;
|
private final Type expectedType;
|
||||||
@Child
|
@Child IsValueOfTypeNode checkType;
|
||||||
IsValueOfTypeNode checkType;
|
@CompilerDirectives.CompilationFinal private String expectedTypeMessage;
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private LazyCheckRootNode lazyCheck;
|
||||||
private String expectedTypeMessage;
|
|
||||||
@CompilerDirectives.CompilationFinal
|
|
||||||
private LazyCheckRootNode lazyCheck;
|
|
||||||
|
|
||||||
TypeCheckNode(String name, Type expectedType) {
|
TypeCheckNode(String name, Type expectedType) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -256,7 +258,8 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(rewriteOn = InvalidAssumptionException.class)
|
@Specialization(rewriteOn = InvalidAssumptionException.class)
|
||||||
Object doCheckNoConversionNeeded(VirtualFrame frame, Object v) throws InvalidAssumptionException {
|
Object doCheckNoConversionNeeded(VirtualFrame frame, Object v)
|
||||||
|
throws InvalidAssumptionException {
|
||||||
var ret = findDirectMatch(frame, v);
|
var ret = findDirectMatch(frame, v);
|
||||||
if (ret != null) {
|
if (ret != null) {
|
||||||
return ret;
|
return ret;
|
||||||
@ -265,26 +268,21 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(limit = "10", guards = {
|
@Specialization(
|
||||||
"cachedType != null",
|
limit = "10",
|
||||||
"findType(typeOfNode, v) == cachedType"
|
guards = {"cachedType != null", "findType(typeOfNode, v) == cachedType"})
|
||||||
})
|
|
||||||
Object doWithConversionCached(
|
Object doWithConversionCached(
|
||||||
VirtualFrame frame, Object v,
|
VirtualFrame frame,
|
||||||
@Shared("typeOfNode")
|
Object v,
|
||||||
@Cached TypeOfNode typeOfNode,
|
@Shared("typeOfNode") @Cached TypeOfNode typeOfNode,
|
||||||
@Cached("findType(typeOfNode, v)") Type cachedType,
|
@Cached("findType(typeOfNode, v)") Type cachedType,
|
||||||
@Cached("findConversionNode(cachedType)") ApplicationNode convertNode
|
@Cached("findConversionNode(cachedType)") ApplicationNode convertNode) {
|
||||||
) {
|
|
||||||
return handleWithConversion(frame, v, convertNode);
|
return handleWithConversion(frame, v, convertNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "doWithConversionCached")
|
@Specialization(replaces = "doWithConversionCached")
|
||||||
Object doWithConversionUncached(
|
Object doWithConversionUncached(
|
||||||
VirtualFrame frame, Object v,
|
VirtualFrame frame, Object v, @Shared("typeOfNode") @Cached TypeOfNode typeOfNode) {
|
||||||
@Shared("typeOfNode")
|
|
||||||
@Cached TypeOfNode typeOfNode
|
|
||||||
) {
|
|
||||||
var type = findType(typeOfNode, v);
|
var type = findType(typeOfNode, v);
|
||||||
return doWithConversionUncachedBoundary(frame == null ? null : frame.materialize(), v, type);
|
return doWithConversionUncachedBoundary(frame == null ? null : frame.materialize(), v, type);
|
||||||
}
|
}
|
||||||
@ -341,20 +339,21 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
var convNode = LiteralNode.build(convAndType.getLeft());
|
var convNode = LiteralNode.build(convAndType.getLeft());
|
||||||
var intoNode = LiteralNode.build(convAndType.getRight());
|
var intoNode = LiteralNode.build(convAndType.getRight());
|
||||||
var valueNode = ran.plainRead();
|
var valueNode = ran.plainRead();
|
||||||
var args = new CallArgument[]{
|
var args =
|
||||||
new CallArgument(null, intoNode),
|
new CallArgument[] {
|
||||||
new CallArgument(null, valueNode)
|
new CallArgument(null, intoNode), new CallArgument(null, valueNode)
|
||||||
};
|
};
|
||||||
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
|
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
|
||||||
} else if (NodeUtil.findParent(this, TypeCheckExpressionNode.class) instanceof TypeCheckExpressionNode tcen) {
|
} else if (NodeUtil.findParent(this, TypeCheckExpressionNode.class)
|
||||||
|
instanceof TypeCheckExpressionNode tcen) {
|
||||||
CompilerAsserts.neverPartOfCompilation();
|
CompilerAsserts.neverPartOfCompilation();
|
||||||
var convNode = LiteralNode.build(convAndType.getLeft());
|
var convNode = LiteralNode.build(convAndType.getLeft());
|
||||||
var intoNode = LiteralNode.build(convAndType.getRight());
|
var intoNode = LiteralNode.build(convAndType.getRight());
|
||||||
var valueNode = tcen.original;
|
var valueNode = tcen.original;
|
||||||
var args = new CallArgument[]{
|
var args =
|
||||||
new CallArgument(null, intoNode),
|
new CallArgument[] {
|
||||||
new CallArgument(null, valueNode)
|
new CallArgument(null, intoNode), new CallArgument(null, valueNode)
|
||||||
};
|
};
|
||||||
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
|
return ApplicationNode.build(convNode, args, DefaultsExecutionMode.EXECUTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,9 +367,8 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object handleWithConversion(
|
private Object handleWithConversion(VirtualFrame frame, Object v, ApplicationNode convertNode)
|
||||||
VirtualFrame frame, Object v, ApplicationNode convertNode
|
throws PanicException {
|
||||||
) throws PanicException {
|
|
||||||
if (convertNode == null) {
|
if (convertNode == null) {
|
||||||
var ret = findDirectMatch(frame, v);
|
var ret = findDirectMatch(frame, v);
|
||||||
if (ret != null) {
|
if (ret != null) {
|
||||||
@ -400,10 +398,9 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class MetaCheckNode extends ReadArgumentCheckNode {
|
abstract static class MetaCheckNode extends ReadArgumentCheckNode {
|
||||||
private final Object expectedMeta;
|
private final Object expectedMeta;
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private String expectedTypeMessage;
|
||||||
private String expectedTypeMessage;
|
|
||||||
|
|
||||||
MetaCheckNode(String name, Object expectedMeta) {
|
MetaCheckNode(String name, Object expectedMeta) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -416,10 +413,7 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization()
|
@Specialization()
|
||||||
Object verifyMetaObject(
|
Object verifyMetaObject(VirtualFrame frame, Object v, @Cached IsValueOfTypeNode isA) {
|
||||||
VirtualFrame frame, Object v,
|
|
||||||
@Cached IsValueOfTypeNode isA
|
|
||||||
) {
|
|
||||||
if (isAllFitValue(v)) {
|
if (isAllFitValue(v)) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -429,6 +423,7 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String expectedTypeMessage() {
|
String expectedTypeMessage() {
|
||||||
if (expectedTypeMessage != null) {
|
if (expectedTypeMessage != null) {
|
||||||
@ -447,18 +442,18 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
|
|
||||||
private static final class LazyCheckRootNode extends RootNode {
|
private static final class LazyCheckRootNode extends RootNode {
|
||||||
|
|
||||||
@Child
|
@Child private ThunkExecutorNode evalThunk;
|
||||||
private ThunkExecutorNode evalThunk;
|
@Child private ReadArgumentCheckNode check;
|
||||||
@Child
|
|
||||||
private ReadArgumentCheckNode check;
|
|
||||||
|
|
||||||
static final FunctionSchema SCHEMA = new FunctionSchema(
|
static final FunctionSchema SCHEMA =
|
||||||
|
new FunctionSchema(
|
||||||
FunctionSchema.CallerFrameAccess.NONE,
|
FunctionSchema.CallerFrameAccess.NONE,
|
||||||
new ArgumentDefinition[]{new ArgumentDefinition(0, "delegate", null, null, ExecutionMode.EXECUTE)},
|
new ArgumentDefinition[] {
|
||||||
new boolean[]{true},
|
new ArgumentDefinition(0, "delegate", null, null, ExecutionMode.EXECUTE)
|
||||||
|
},
|
||||||
|
new boolean[] {true},
|
||||||
new CallArgumentInfo[0],
|
new CallArgumentInfo[0],
|
||||||
new Annotation[0]
|
new Annotation[0]);
|
||||||
);
|
|
||||||
|
|
||||||
LazyCheckRootNode(TruffleLanguage<?> language, ReadArgumentCheckNode check) {
|
LazyCheckRootNode(TruffleLanguage<?> language, ReadArgumentCheckNode check) {
|
||||||
super(language);
|
super(language);
|
||||||
@ -467,7 +462,7 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Function wrapThunk(Function thunk) {
|
Function wrapThunk(Function thunk) {
|
||||||
return new Function(getCallTarget(), thunk.getScope(), SCHEMA, new Object[]{thunk}, null);
|
return new Function(getCallTarget(), thunk.getScope(), SCHEMA, new Object[] {thunk}, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -483,10 +478,8 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class TypeCheckExpressionNode extends ExpressionNode {
|
private static final class TypeCheckExpressionNode extends ExpressionNode {
|
||||||
@Child
|
@Child private ExpressionNode original;
|
||||||
private ExpressionNode original;
|
@Child private ReadArgumentCheckNode check;
|
||||||
@Child
|
|
||||||
private ReadArgumentCheckNode check;
|
|
||||||
|
|
||||||
TypeCheckExpressionNode(ExpressionNode original, ReadArgumentCheckNode check) {
|
TypeCheckExpressionNode(ExpressionNode original, ReadArgumentCheckNode check) {
|
||||||
this.check = check;
|
this.check = check;
|
||||||
@ -505,5 +498,4 @@ public abstract class ReadArgumentCheckNode extends Node {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.oracle.truffle.api.CompilerDirectives;
|
|||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
import org.enso.interpreter.node.BaseNode;
|
import org.enso.interpreter.node.BaseNode;
|
||||||
import org.enso.interpreter.node.callable.ExecuteCallNode;
|
import org.enso.interpreter.node.callable.ExecuteCallNode;
|
||||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||||
@ -16,8 +17,6 @@ import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
|||||||
import org.enso.interpreter.runtime.control.TailCallException;
|
import org.enso.interpreter.runtime.control.TailCallException;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
|
|
||||||
/** Handles runtime function currying and oversaturated (eta-expanded) calls. */
|
/** Handles runtime function currying and oversaturated (eta-expanded) calls. */
|
||||||
@NodeInfo(description = "Handles runtime currying and eta-expansion")
|
@NodeInfo(description = "Handles runtime currying and eta-expansion")
|
||||||
public class CurryNode extends BaseNode {
|
public class CurryNode extends BaseNode {
|
||||||
@ -107,8 +106,9 @@ public class CurryNode extends BaseNode {
|
|||||||
if (!postApplicationSchema.hasOversaturatedArgs()) {
|
if (!postApplicationSchema.hasOversaturatedArgs()) {
|
||||||
var value = doCall(frame, function, callerInfo, state, arguments);
|
var value = doCall(frame, function, callerInfo, state, arguments);
|
||||||
if (defaultsExecutionMode.isExecute()
|
if (defaultsExecutionMode.isExecute()
|
||||||
&& (value instanceof Function || (value instanceof AtomConstructor cons
|
&& (value instanceof Function
|
||||||
&& cons.getConstructorFunction().getSchema().isFullyApplied()))) {
|
|| (value instanceof AtomConstructor cons
|
||||||
|
&& cons.getConstructorFunction().getSchema().isFullyApplied()))) {
|
||||||
keepExecutingProfile.enter();
|
keepExecutingProfile.enter();
|
||||||
if (oversaturatedCallableNode == null) {
|
if (oversaturatedCallableNode == null) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
@ -133,24 +133,28 @@ public class CurryNode extends BaseNode {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var evaluatedVal = loopingCall.executeDispatch(frame, function, callerInfo, state, arguments, null);
|
var evaluatedVal =
|
||||||
|
loopingCall.executeDispatch(frame, function, callerInfo, state, arguments, null);
|
||||||
|
|
||||||
return this.oversaturatedCallableNode.execute(
|
return this.oversaturatedCallableNode.execute(
|
||||||
evaluatedVal, frame, state, oversaturatedArguments);
|
evaluatedVal, frame, state, oversaturatedArguments);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return
|
return new Function(
|
||||||
new Function(
|
function.getCallTarget(),
|
||||||
function.getCallTarget(),
|
function.getScope(),
|
||||||
function.getScope(),
|
postApplicationSchema,
|
||||||
postApplicationSchema,
|
arguments,
|
||||||
arguments,
|
oversaturatedArguments);
|
||||||
oversaturatedArguments);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object doCall(
|
private Object doCall(
|
||||||
VirtualFrame frame, Function function, CallerInfo callerInfo, State state, Object[] arguments) {
|
VirtualFrame frame,
|
||||||
|
Function function,
|
||||||
|
CallerInfo callerInfo,
|
||||||
|
State state,
|
||||||
|
Object[] arguments) {
|
||||||
return switch (getTailStatus()) {
|
return switch (getTailStatus()) {
|
||||||
case TAIL_DIRECT -> directCall.executeCall(frame, function, callerInfo, state, arguments);
|
case TAIL_DIRECT -> directCall.executeCall(frame, function, callerInfo, state, arguments);
|
||||||
case TAIL_LOOP -> throw new TailCallException(function, callerInfo, arguments);
|
case TAIL_LOOP -> throw new TailCallException(function, callerInfo, arguments);
|
||||||
|
@ -77,8 +77,9 @@ public abstract class IndirectCurryNode extends Node {
|
|||||||
var value =
|
var value =
|
||||||
doCall(frame, function, callerInfo, state, arguments, isTail, directCall, loopingCall);
|
doCall(frame, function, callerInfo, state, arguments, isTail, directCall, loopingCall);
|
||||||
if (defaultsExecutionMode.isExecute()
|
if (defaultsExecutionMode.isExecute()
|
||||||
&& (value instanceof Function || (value instanceof AtomConstructor cons
|
&& (value instanceof Function
|
||||||
&& cons.getConstructorFunction().getSchema().isFullyApplied()))) {
|
|| (value instanceof AtomConstructor cons
|
||||||
|
&& cons.getConstructorFunction().getSchema().isFullyApplied()))) {
|
||||||
return oversaturatedCallableNode.execute(
|
return oversaturatedCallableNode.execute(
|
||||||
value,
|
value,
|
||||||
frame,
|
frame,
|
||||||
@ -92,7 +93,8 @@ public abstract class IndirectCurryNode extends Node {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var evaluatedVal = loopingCall.executeDispatch(frame, function, callerInfo, state, arguments, null);
|
var evaluatedVal =
|
||||||
|
loopingCall.executeDispatch(frame, function, callerInfo, state, arguments, null);
|
||||||
|
|
||||||
return oversaturatedCallableNode.execute(
|
return oversaturatedCallableNode.execute(
|
||||||
evaluatedVal,
|
evaluatedVal,
|
||||||
@ -106,11 +108,11 @@ public abstract class IndirectCurryNode extends Node {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new Function(
|
return new Function(
|
||||||
function.getCallTarget(),
|
function.getCallTarget(),
|
||||||
function.getScope(),
|
function.getScope(),
|
||||||
postApplicationSchema,
|
postApplicationSchema,
|
||||||
arguments,
|
arguments,
|
||||||
oversaturatedArguments);
|
oversaturatedArguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,8 @@ public abstract class InvokeFunctionNode extends BaseNode {
|
|||||||
@Cached("build(cachedSchema, argumentMapping, getArgumentsExecutionMode())")
|
@Cached("build(cachedSchema, argumentMapping, getArgumentsExecutionMode())")
|
||||||
ArgumentSorterNode mappingNode,
|
ArgumentSorterNode mappingNode,
|
||||||
@Cached(
|
@Cached(
|
||||||
"build(argumentMapping, getDefaultsExecutionMode(), getArgumentsExecutionMode(), getTailStatus())")
|
"build(argumentMapping, getDefaultsExecutionMode(), getArgumentsExecutionMode(),"
|
||||||
|
+ " getTailStatus())")
|
||||||
CurryNode curryNode) {
|
CurryNode curryNode) {
|
||||||
ArgumentSorterNode.MappedArguments mappedArguments =
|
ArgumentSorterNode.MappedArguments mappedArguments =
|
||||||
mappingNode.execute(callerFrame, function, state, arguments);
|
mappingNode.execute(callerFrame, function, state, arguments);
|
||||||
@ -201,7 +202,9 @@ public abstract class InvokeFunctionNode extends BaseNode {
|
|||||||
return argumentsExecutionMode;
|
return argumentsExecutionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the source section for this node. */
|
/**
|
||||||
|
* @return the source section for this node.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SourceSection getSourceSection() {
|
public SourceSection getSourceSection() {
|
||||||
Node parent = getParent();
|
Node parent = getParent();
|
||||||
|
@ -80,8 +80,7 @@ public class CreateFunctionNode extends ExpressionNode {
|
|||||||
return schema.getArgumentInfos();
|
return schema.getArgumentInfos();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Optionally offers {@link AvoidIdInstrumentationTag}.
|
/** Optionally offers {@link AvoidIdInstrumentationTag}. */
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasTag(Class<? extends Tag> tag) {
|
public boolean hasTag(Class<? extends Tag> tag) {
|
||||||
if (AvoidIdInstrumentationTag.class == tag) {
|
if (AvoidIdInstrumentationTag.class == tag) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.enso.interpreter.node.controlflow.caseexpr;
|
package org.enso.interpreter.node.controlflow.caseexpr;
|
||||||
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.EnsoObject;
|
import org.enso.interpreter.runtime.data.EnsoObject;
|
||||||
|
|
||||||
@ -13,5 +12,4 @@ record BranchResult(boolean isMatched, Object result) implements EnsoObject {
|
|||||||
static BranchResult success(Object result) {
|
static BranchResult success(Object result) {
|
||||||
return new BranchResult(true, result);
|
return new BranchResult(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
package org.enso.interpreter.node.controlflow.caseexpr;
|
package org.enso.interpreter.node.controlflow.caseexpr;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.RootCallTarget;
|
import com.oracle.truffle.api.RootCallTarget;
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
@ -13,6 +9,8 @@ import com.oracle.truffle.api.interop.InteropLibrary;
|
|||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
import com.oracle.truffle.api.profiles.CountingConditionProfile;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
|
|
||||||
@NodeInfo(shortName = "NumericLiteralMatch", description = "Allows matching on numeric literals")
|
@NodeInfo(shortName = "NumericLiteralMatch", description = "Allows matching on numeric literals")
|
||||||
public abstract class NumericLiteralBranchNode extends BranchNode {
|
public abstract class NumericLiteralBranchNode extends BranchNode {
|
||||||
@ -46,19 +44,20 @@ public abstract class NumericLiteralBranchNode extends BranchNode {
|
|||||||
Object state,
|
Object state,
|
||||||
Object target,
|
Object target,
|
||||||
@CachedLibrary(limit = "1") InteropLibrary interop) {
|
@CachedLibrary(limit = "1") InteropLibrary interop) {
|
||||||
var taken = switch (literal) {
|
var taken =
|
||||||
case Long l -> target instanceof Long t && l.longValue() == t.longValue();
|
switch (literal) {
|
||||||
case Double d -> target instanceof Double t && d.doubleValue() == t.doubleValue();
|
case Long l -> target instanceof Long t && l.longValue() == t.longValue();
|
||||||
case BigInteger b -> target instanceof EnsoBigInteger e && compare(b, e.asBigInteger());
|
case Double d -> target instanceof Double t && d.doubleValue() == t.doubleValue();
|
||||||
default -> throw CompilerDirectives.shouldNotReachHere();
|
case BigInteger b -> target instanceof EnsoBigInteger e && compare(b, e.asBigInteger());
|
||||||
};
|
default -> throw CompilerDirectives.shouldNotReachHere();
|
||||||
|
};
|
||||||
if (numProfile.profile(taken)) accept(frame, state, new Object[0]);
|
if (numProfile.profile(taken)) accept(frame, state, new Object[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
void doOther(VirtualFrame frame, Object state, Object target) {}
|
void doOther(VirtualFrame frame, Object state, Object target) {}
|
||||||
|
|
||||||
@CompilerDirectives.TruffleBoundary(allowInlining=true)
|
@CompilerDirectives.TruffleBoundary(allowInlining = true)
|
||||||
private boolean compare(BigInteger b1, BigInteger b2) {
|
private boolean compare(BigInteger b1, BigInteger b2) {
|
||||||
return b1.equals(b2);
|
return b1.equals(b2);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ public class QualifiedAccessorNode extends RootNode {
|
|||||||
this.atomConstructor = atomConstructor;
|
this.atomConstructor = atomConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the atom constructor. */
|
/**
|
||||||
|
* @return the atom constructor.
|
||||||
|
*/
|
||||||
public AtomConstructor getAtomConstructor() {
|
public AtomConstructor getAtomConstructor() {
|
||||||
return atomConstructor;
|
return atomConstructor;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin;
|
package org.enso.interpreter.node.expression.builtin;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
|
|
||||||
/** A base class for all classes annotated with @BuiltinType */
|
/** A base class for all classes annotated with @BuiltinType */
|
||||||
public abstract class Builtin {
|
public abstract class Builtin {
|
||||||
public record Cons(String name, List<String> params) {
|
public record Cons(String name, List<String> params) {
|
||||||
@ -20,8 +19,10 @@ public abstract class Builtin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AtomConstructor build(EnsoLanguage language, ModuleScope scope, Type type) {
|
private AtomConstructor build(EnsoLanguage language, ModuleScope scope, Type type) {
|
||||||
var res = new AtomConstructor(name, scope, type,true);
|
var res = new AtomConstructor(name, scope, type, true);
|
||||||
res.initializeFields(language, IntStream.range(0, params.size())
|
res.initializeFields(
|
||||||
|
language,
|
||||||
|
IntStream.range(0, params.size())
|
||||||
.mapToObj(
|
.mapToObj(
|
||||||
i ->
|
i ->
|
||||||
new ArgumentDefinition(
|
new ArgumentDefinition(
|
||||||
@ -35,7 +36,6 @@ public abstract class Builtin {
|
|||||||
|
|
||||||
public Builtin() {
|
public Builtin() {
|
||||||
name = this.getClass().getSimpleName().replaceAll("([^_A-Z])([A-Z])", "$1_$2");
|
name = this.getClass().getSimpleName().replaceAll("([^_A-Z])([A-Z])", "$1_$2");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @CompilerDirectives.CompilationFinal Type type;
|
private @CompilerDirectives.CompilationFinal Type type;
|
||||||
@ -49,7 +49,8 @@ public abstract class Builtin {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void initialize(EnsoLanguage language, ModuleScope scope, Map<Class<? extends Builtin>, Builtin> builtins) {
|
public final void initialize(
|
||||||
|
EnsoLanguage language, ModuleScope scope, Map<Class<? extends Builtin>, Builtin> builtins) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
Type supertype = null;
|
Type supertype = null;
|
||||||
if (getSuperType() != null) {
|
if (getSuperType() != null) {
|
||||||
@ -57,9 +58,10 @@ public abstract class Builtin {
|
|||||||
s.initialize(language, scope, builtins);
|
s.initialize(language, scope, builtins);
|
||||||
supertype = s.getType();
|
supertype = s.getType();
|
||||||
}
|
}
|
||||||
type = containsValues() ?
|
type =
|
||||||
Type.create(name, scope, supertype, builtins.get(Any.class).getType(), true) :
|
containsValues()
|
||||||
Type.createSingleton(name, scope, supertype, true);
|
? Type.create(name, scope, supertype, builtins.get(Any.class).getType(), true)
|
||||||
|
: Type.createSingleton(name, scope, supertype, true);
|
||||||
}
|
}
|
||||||
if (constructors == null) {
|
if (constructors == null) {
|
||||||
var conses = getDeclaredConstructors();
|
var conses = getDeclaredConstructors();
|
||||||
@ -91,5 +93,4 @@ public abstract class Builtin {
|
|||||||
public final AtomConstructor[] getConstructors() {
|
public final AtomConstructor[] getConstructors() {
|
||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
|||||||
type = "Any",
|
type = "Any",
|
||||||
name = "catch_primitive",
|
name = "catch_primitive",
|
||||||
description =
|
description =
|
||||||
"If called on an error, executes the provided handler on the error's payload. Otherwise acts as identity.")
|
"If called on an error, executes the provided handler on the error's payload. Otherwise"
|
||||||
|
+ " acts as identity.")
|
||||||
public class CatchAnyNode extends Node {
|
public class CatchAnyNode extends Node {
|
||||||
private @Child InvokeCallableNode invokeCallableNode;
|
private @Child InvokeCallableNode invokeCallableNode;
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@ import org.enso.interpreter.runtime.state.State;
|
|||||||
type = "Error",
|
type = "Error",
|
||||||
name = "catch_primitive",
|
name = "catch_primitive",
|
||||||
description =
|
description =
|
||||||
"If called on an error, executes the provided handler on the error's payload. Otherwise acts as identity.")
|
"If called on an error, executes the provided handler on the error's payload. Otherwise"
|
||||||
|
+ " acts as identity.")
|
||||||
public class CatchErrorNode extends Node {
|
public class CatchErrorNode extends Node {
|
||||||
private @Child InvokeCallableNode invokeCallableNode;
|
private @Child InvokeCallableNode invokeCallableNode;
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ import org.enso.interpreter.runtime.error.PanicException;
|
|||||||
type = "Vector",
|
type = "Vector",
|
||||||
name = "from_polyglot_array",
|
name = "from_polyglot_array",
|
||||||
description =
|
description =
|
||||||
"Creates a Vector by providing its underlying storage as a polyglot array. The underlying array should be guaranteed to never be mutated.",
|
"Creates a Vector by providing its underlying storage as a polyglot array. The underlying"
|
||||||
|
+ " array should be guaranteed to never be mutated.",
|
||||||
autoRegister = false)
|
autoRegister = false)
|
||||||
public abstract class FromPolyglotArrayBuiltinVectorNode extends Node {
|
public abstract class FromPolyglotArrayBuiltinVectorNode extends Node {
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ public abstract class HostValueToEnsoNode extends Node {
|
|||||||
public static HostValueToEnsoNode getUncached() {
|
public static HostValueToEnsoNode getUncached() {
|
||||||
return HostValueToEnsoNodeGen.getUncached();
|
return HostValueToEnsoNodeGen.getUncached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an arbitrary value to a value usable within Enso code.
|
* Converts an arbitrary value to a value usable within Enso code.
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.meta;
|
package org.enso.interpreter.node.expression.builtin.meta;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.NeverDefault;
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||||
|
import com.oracle.truffle.api.library.ExportLibrary;
|
||||||
|
import com.oracle.truffle.api.library.ExportMessage;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.nodes.RootNode;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||||
@ -16,19 +27,6 @@ import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
|||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.NeverDefault;
|
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.TruffleObject;
|
|
||||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
|
||||||
import com.oracle.truffle.api.library.ExportLibrary;
|
|
||||||
import com.oracle.truffle.api.library.ExportMessage;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.nodes.RootNode;
|
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Meta",
|
type = "Meta",
|
||||||
name = "atom_with_hole_builtin",
|
name = "atom_with_hole_builtin",
|
||||||
@ -49,22 +47,21 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
@NeverDefault
|
@NeverDefault
|
||||||
static InvokeCallableNode callWithHole() {
|
static InvokeCallableNode callWithHole() {
|
||||||
return InvokeCallableNode.build(
|
return InvokeCallableNode.build(
|
||||||
new CallArgumentInfo[] {new CallArgumentInfo()},
|
new CallArgumentInfo[] {new CallArgumentInfo()},
|
||||||
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
|
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
|
||||||
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
|
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
Object doExecute(
|
Object doExecute(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
Object factory,
|
Object factory,
|
||||||
State state,
|
State state,
|
||||||
@Cached("callWithHole()") InvokeCallableNode iop,
|
@Cached("callWithHole()") InvokeCallableNode iop,
|
||||||
@Cached SwapAtomFieldNode swapNode
|
@Cached SwapAtomFieldNode swapNode) {
|
||||||
) {
|
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var lazy = new HoleInAtom();
|
var lazy = new HoleInAtom();
|
||||||
var result = iop.execute(factory, frame, state, new Object[] { lazy });
|
var result = iop.execute(factory, frame, state, new Object[] {lazy});
|
||||||
if (result instanceof Atom atom) {
|
if (result instanceof Atom atom) {
|
||||||
var index = swapNode.findHoleIndex(atom, lazy);
|
var index = swapNode.findHoleIndex(atom, lazy);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@ -82,8 +79,7 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
int index;
|
int index;
|
||||||
Function function;
|
Function function;
|
||||||
|
|
||||||
HoleInAtom() {
|
HoleInAtom() {}
|
||||||
}
|
|
||||||
|
|
||||||
void init(Atom result, int index, Function function) {
|
void init(Atom result, int index, Function function) {
|
||||||
this.result = result;
|
this.result = result;
|
||||||
@ -91,26 +87,30 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage boolean hasMembers() {
|
@ExportMessage
|
||||||
return true;
|
boolean hasMembers() {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage boolean isMemberReadable(String member) {
|
@ExportMessage
|
||||||
return switch (member) {
|
boolean isMemberReadable(String member) {
|
||||||
case "value", "fill" -> true;
|
return switch (member) {
|
||||||
default -> false;
|
case "value", "fill" -> true;
|
||||||
};
|
default -> false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage boolean isMemberInvocable(String member) {
|
@ExportMessage
|
||||||
return switch (member) {
|
boolean isMemberInvocable(String member) {
|
||||||
case "fill" -> true;
|
return switch (member) {
|
||||||
default -> false;
|
case "fill" -> true;
|
||||||
};
|
default -> false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage Object getMembers(boolean includeInternal) {
|
@ExportMessage
|
||||||
return ArrayLikeHelpers.wrapStrings("value", "fill");
|
Object getMembers(boolean includeInternal) {
|
||||||
|
return ArrayLikeHelpers.wrapStrings("value", "fill");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
@ -126,9 +126,10 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
|
|
||||||
@ExportMessage
|
@ExportMessage
|
||||||
Object invokeMember(
|
Object invokeMember(
|
||||||
String name, Object[] args,
|
String name,
|
||||||
@Cached(value="buildWithArity(1)", allowUncached=true) InvokeFunctionNode invoke
|
Object[] args,
|
||||||
) throws UnknownIdentifierException {
|
@Cached(value = "buildWithArity(1)", allowUncached = true) InvokeFunctionNode invoke)
|
||||||
|
throws UnknownIdentifierException {
|
||||||
if ("fill".equals(name)) {
|
if ("fill".equals(name)) {
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
return function;
|
return function;
|
||||||
@ -144,20 +145,26 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
return "Meta.atom_with_hole";
|
return "Meta.atom_with_hole";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class SwapAtomFieldNode extends RootNode {
|
static final class SwapAtomFieldNode extends RootNode {
|
||||||
private final FunctionSchema schema;
|
private final FunctionSchema schema;
|
||||||
@CompilerDirectives.CompilationFinal
|
@CompilerDirectives.CompilationFinal private int lastIndex = -1;
|
||||||
private int lastIndex = -1;
|
|
||||||
@Child private StructsLibrary structs = StructsLibrary.getFactory().createDispatched(10);
|
@Child private StructsLibrary structs = StructsLibrary.getFactory().createDispatched(10);
|
||||||
|
|
||||||
private SwapAtomFieldNode() {
|
private SwapAtomFieldNode() {
|
||||||
super(null);
|
super(null);
|
||||||
this.schema = new FunctionSchema(FunctionSchema.CallerFrameAccess.NONE, new ArgumentDefinition[]{
|
this.schema =
|
||||||
new ArgumentDefinition(0, "lazy", null, null, ArgumentDefinition.ExecutionMode.EXECUTE),
|
new FunctionSchema(
|
||||||
new ArgumentDefinition(1, "value", null, null, ArgumentDefinition.ExecutionMode.EXECUTE)
|
FunctionSchema.CallerFrameAccess.NONE,
|
||||||
}, new boolean[]{
|
new ArgumentDefinition[] {
|
||||||
true, false
|
new ArgumentDefinition(
|
||||||
}, new CallArgumentInfo[0], new Annotation[0]);
|
0, "lazy", null, null, ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||||
|
new ArgumentDefinition(
|
||||||
|
1, "value", null, null, ArgumentDefinition.ExecutionMode.EXECUTE)
|
||||||
|
},
|
||||||
|
new boolean[] {true, false},
|
||||||
|
new CallArgumentInfo[0],
|
||||||
|
new Annotation[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NeverDefault
|
@NeverDefault
|
||||||
@ -191,23 +198,17 @@ public abstract class AtomWithAHoleNode extends Node {
|
|||||||
|
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
private int findHoleIndexLoop(Object[] arr, HoleInAtom lazy) {
|
private int findHoleIndexLoop(Object[] arr, HoleInAtom lazy) {
|
||||||
for (int i = 0; i < arr.length; i++) {
|
for (int i = 0; i < arr.length; i++) {
|
||||||
if (arr[i] == lazy) {
|
if (arr[i] == lazy) {
|
||||||
return i;
|
return i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return -1;
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Function createFn(HoleInAtom lazy) {
|
Function createFn(HoleInAtom lazy) {
|
||||||
var preArgs = new Object[]{lazy, null};
|
var preArgs = new Object[] {lazy, null};
|
||||||
return new Function(
|
return new Function(getCallTarget(), null, schema, preArgs, new Object[] {});
|
||||||
getCallTarget(),
|
|
||||||
null,
|
|
||||||
schema,
|
|
||||||
preArgs,
|
|
||||||
new Object[]{}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,12 +31,8 @@ public abstract class EnsoProjectNode extends Node {
|
|||||||
return EnsoProjectNodeGen.create();
|
return EnsoProjectNodeGen.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A weak reference to the context in which this node was last executed. */
|
||||||
/**
|
@CompilationFinal private WeakReference<EnsoContext> previousCtxRef = new WeakReference<>(null);
|
||||||
* A weak reference to the context in which this node was last executed.
|
|
||||||
*/
|
|
||||||
@CompilationFinal
|
|
||||||
private WeakReference<EnsoContext> previousCtxRef = new WeakReference<>(null);
|
|
||||||
|
|
||||||
private Object cachedProjectDescr;
|
private Object cachedProjectDescr;
|
||||||
|
|
||||||
@ -72,7 +68,8 @@ public abstract class EnsoProjectNode extends Node {
|
|||||||
: "Should skip the first frame, therefore, callNode should not be null";
|
: "Should skip the first frame, therefore, callNode should not be null";
|
||||||
var callRootNode = callNode.getRootNode();
|
var callRootNode = callNode.getRootNode();
|
||||||
assert callRootNode != null
|
assert callRootNode != null
|
||||||
: "Should be called only from Enso code, and thus, should always have a root node";
|
: "Should be called only from Enso code, and thus, should always have a"
|
||||||
|
+ " root node";
|
||||||
if (callRootNode instanceof EnsoRootNode ensoRootNode) {
|
if (callRootNode instanceof EnsoRootNode ensoRootNode) {
|
||||||
var pkg = ensoRootNode.getModuleScope().getModule().getPackage();
|
var pkg = ensoRootNode.getModuleScope().getModule().getPackage();
|
||||||
// Don't return null, as that would signal to Truffle that we want to
|
// Don't return null, as that would signal to Truffle that we want to
|
||||||
@ -84,17 +81,19 @@ public abstract class EnsoProjectNode extends Node {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this,
|
throw EnsoContext.get(this)
|
||||||
"Should not reach here: callRootNode = "
|
.raiseAssertionPanic(
|
||||||
+ callRootNode
|
this,
|
||||||
+ ". Probably not called from Enso?", null);
|
"Should not reach here: callRootNode = "
|
||||||
|
+ callRootNode
|
||||||
|
+ ". Probably not called from Enso?",
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// The first frame is always Enso_Project.enso_project
|
// The first frame is always Enso_Project.enso_project
|
||||||
1);
|
1);
|
||||||
if (pkgOpt.isPresent()) {
|
if (pkgOpt.isPresent()) {
|
||||||
cachedProjectDescr =
|
cachedProjectDescr = createProjectDescriptionAtom(ctx, pkgOpt.get());
|
||||||
createProjectDescriptionAtom(ctx, pkgOpt.get());
|
|
||||||
} else {
|
} else {
|
||||||
cachedProjectDescr = notInModuleError(ctx);
|
cachedProjectDescr = notInModuleError(ctx);
|
||||||
}
|
}
|
||||||
@ -106,8 +105,7 @@ public abstract class EnsoProjectNode extends Node {
|
|||||||
@Specialization(guards = "!isNothing(module)")
|
@Specialization(guards = "!isNothing(module)")
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public Object getOtherProjectDescr(
|
public Object getOtherProjectDescr(
|
||||||
Object module,
|
Object module, @CachedLibrary(limit = "5") TypesLibrary typesLib) {
|
||||||
@CachedLibrary(limit = "5") TypesLibrary typesLib) {
|
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
if (!typesLib.hasType(module)) {
|
if (!typesLib.hasType(module)) {
|
||||||
return unsupportedArgsError(module);
|
return unsupportedArgsError(module);
|
||||||
@ -140,7 +138,7 @@ public abstract class EnsoProjectNode extends Node {
|
|||||||
.getBuiltins()
|
.getBuiltins()
|
||||||
.error()
|
.error()
|
||||||
.makeUnsupportedArgumentsError(
|
.makeUnsupportedArgumentsError(
|
||||||
new Object[]{moduleActual}, "The `module` argument does not refer to a module"),
|
new Object[] {moduleActual}, "The `module` argument does not refer to a module"),
|
||||||
this);
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,5 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.meta;
|
package org.enso.interpreter.node.expression.builtin.meta;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import org.enso.interpreter.dsl.AcceptsError;
|
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
|
||||||
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
|
||||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
|
||||||
import org.enso.interpreter.runtime.data.EnsoMultiValue;
|
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
|
||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
|
||||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
@ -24,6 +10,18 @@ import com.oracle.truffle.api.interop.TruffleObject;
|
|||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.enso.interpreter.dsl.AcceptsError;
|
||||||
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
|
import org.enso.interpreter.node.expression.builtin.number.utils.BigIntegerOps;
|
||||||
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
|
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||||
|
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||||
|
import org.enso.interpreter.runtime.data.EnsoMultiValue;
|
||||||
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
|
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||||
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
|
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Any",
|
type = "Any",
|
||||||
@ -76,11 +74,11 @@ public abstract class EqualsNode extends Node {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards="interop.isBoolean(other)")
|
@Specialization(guards = "interop.isBoolean(other)")
|
||||||
boolean equalsBoolInterop(
|
boolean equalsBoolInterop(
|
||||||
boolean self, Object other,
|
boolean self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
|
Object other,
|
||||||
) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
try {
|
try {
|
||||||
return self == interop.asBoolean(other);
|
return self == interop.asBoolean(other);
|
||||||
} catch (UnsupportedMessageException ex) {
|
} catch (UnsupportedMessageException ex) {
|
||||||
@ -108,11 +106,11 @@ public abstract class EqualsNode extends Node {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards="interop.fitsInLong(other)")
|
@Specialization(guards = "interop.fitsInLong(other)")
|
||||||
boolean equalsLongInterop(
|
boolean equalsLongInterop(
|
||||||
long self, Object other,
|
long self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
|
Object other,
|
||||||
) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
try {
|
try {
|
||||||
return self == interop.asLong(other);
|
return self == interop.asLong(other);
|
||||||
} catch (UnsupportedMessageException ex) {
|
} catch (UnsupportedMessageException ex) {
|
||||||
@ -145,11 +143,11 @@ public abstract class EqualsNode extends Node {
|
|||||||
return self == other.getValue().doubleValue();
|
return self == other.getValue().doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards="interop.fitsInDouble(other)")
|
@Specialization(guards = "interop.fitsInDouble(other)")
|
||||||
boolean equalsDoubleInterop(
|
boolean equalsDoubleInterop(
|
||||||
double self, Object other,
|
double self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
|
Object other,
|
||||||
) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
try {
|
try {
|
||||||
return self == interop.asDouble(other);
|
return self == interop.asDouble(other);
|
||||||
} catch (UnsupportedMessageException ex) {
|
} catch (UnsupportedMessageException ex) {
|
||||||
@ -195,14 +193,11 @@ public abstract class EqualsNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@Specialization(guards={
|
@Specialization(guards = {"!isPrimitiveValue(other)", "interop.fitsInBigInteger(other)"})
|
||||||
"!isPrimitiveValue(other)",
|
|
||||||
"interop.fitsInBigInteger(other)"
|
|
||||||
})
|
|
||||||
boolean equalsBigIntInterop(
|
boolean equalsBigIntInterop(
|
||||||
EnsoBigInteger self, Object other,
|
EnsoBigInteger self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop
|
Object other,
|
||||||
) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
try {
|
try {
|
||||||
var otherBigInteger = InteropLibrary.getUncached().asBigInteger(other);
|
var otherBigInteger = InteropLibrary.getUncached().asBigInteger(other);
|
||||||
return self.asBigInteger().equals(otherBigInteger);
|
return self.asBigInteger().equals(otherBigInteger);
|
||||||
@ -293,40 +288,39 @@ public abstract class EqualsNode extends Node {
|
|||||||
return isSameObjectNode.execute(self, other) || equalsAtomNode.execute(self, other);
|
return isSameObjectNode.execute(self, other) || equalsAtomNode.execute(self, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsReverseBoolean(
|
boolean equalsReverseBoolean(
|
||||||
TruffleObject self, boolean other,
|
TruffleObject self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
boolean other,
|
||||||
@Shared("reverse") @Cached EqualsNode reverse
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
) {
|
@Shared("reverse") @Cached EqualsNode reverse) {
|
||||||
return reverse.execute(other, self);
|
return reverse.execute(other, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsReverseLong(
|
boolean equalsReverseLong(
|
||||||
TruffleObject self, long other,
|
TruffleObject self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
long other,
|
||||||
@Shared("reverse") @Cached EqualsNode reverse
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
) {
|
@Shared("reverse") @Cached EqualsNode reverse) {
|
||||||
return reverse.execute(other, self);
|
return reverse.execute(other, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsReverseDouble(
|
boolean equalsReverseDouble(
|
||||||
TruffleObject self, double other,
|
TruffleObject self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
double other,
|
||||||
@Shared("reverse") @Cached EqualsNode reverse
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
) {
|
@Shared("reverse") @Cached EqualsNode reverse) {
|
||||||
return reverse.execute(other, self);
|
return reverse.execute(other, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
boolean equalsReverseBigInt(
|
boolean equalsReverseBigInt(
|
||||||
TruffleObject self, EnsoBigInteger other,
|
TruffleObject self,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
EnsoBigInteger other,
|
||||||
@Shared("reverse") @Cached EqualsNode reverse
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
) {
|
@Shared("reverse") @Cached EqualsNode reverse) {
|
||||||
return reverse.execute(other, self);
|
return reverse.execute(other, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,8 +369,6 @@ public abstract class EqualsNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean isPrimitiveValue(Object object) {
|
static boolean isPrimitiveValue(Object object) {
|
||||||
return object instanceof Boolean
|
return object instanceof Boolean || object instanceof Long || object instanceof Double;
|
||||||
|| object instanceof Long
|
|
||||||
|| object instanceof Double;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,11 @@ public abstract class GetAnnotationNode extends BaseNode {
|
|||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var err = ctx.getBuiltins().error();
|
var err = ctx.getBuiltins().error();
|
||||||
var payload = err.makeUnsupportedArgumentsError(new Object[] { method }, "Use .name to specify name of function");
|
var payload =
|
||||||
|
err.makeUnsupportedArgumentsError(
|
||||||
|
new Object[] {method}, "Use .name to specify name of function");
|
||||||
throw new PanicException(payload, this);
|
throw new PanicException(payload, this);
|
||||||
}
|
}
|
||||||
if (methodFunction != null) {
|
if (methodFunction != null) {
|
||||||
String parameterName = expectStringNode.execute(parameter);
|
String parameterName = expectStringNode.execute(parameter);
|
||||||
Annotation annotation = methodFunction.getSchema().getAnnotation(parameterName);
|
Annotation annotation = methodFunction.getSchema().getAnnotation(parameterName);
|
||||||
|
@ -16,10 +16,11 @@ public class GetQualifiedTypeNameNode extends Node {
|
|||||||
private @Child TypeOfNode typeOfNode = TypeOfNode.build();
|
private @Child TypeOfNode typeOfNode = TypeOfNode.build();
|
||||||
|
|
||||||
Object execute(@AcceptsError Object value) {
|
Object execute(@AcceptsError Object value) {
|
||||||
var maybeType = switch (value) {
|
var maybeType =
|
||||||
case Type type -> type;
|
switch (value) {
|
||||||
default -> typeOfNode.execute(value);
|
case Type type -> type;
|
||||||
};
|
default -> typeOfNode.execute(value);
|
||||||
|
};
|
||||||
if (maybeType instanceof Type type) {
|
if (maybeType instanceof Type type) {
|
||||||
return Text.create(type.getQualifiedName().toString());
|
return Text.create(type.getQualifiedName().toString());
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,31 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.meta;
|
package org.enso.interpreter.node.expression.builtin.meta;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.oracle.truffle.api.CompilerAsserts;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
|
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||||
|
import com.oracle.truffle.api.dsl.NeverDefault;
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.interop.ArityException;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||||
|
import com.oracle.truffle.api.interop.StopIterationException;
|
||||||
|
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
||||||
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import com.oracle.truffle.api.profiles.ConditionProfile;
|
||||||
|
import com.oracle.truffle.api.profiles.LoopConditionProfile;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.enso.interpreter.dsl.AcceptsError;
|
import org.enso.interpreter.dsl.AcceptsError;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
|
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
|
||||||
@ -33,29 +54,6 @@ import org.enso.interpreter.runtime.scope.ModuleScope;
|
|||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
import org.enso.polyglot.common_utils.Core_Text_Utils;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.oracle.truffle.api.CompilerAsserts;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
|
||||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
|
||||||
import com.oracle.truffle.api.dsl.NeverDefault;
|
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
|
||||||
import com.oracle.truffle.api.interop.ArityException;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
|
||||||
import com.oracle.truffle.api.interop.StopIterationException;
|
|
||||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
import com.oracle.truffle.api.profiles.ConditionProfile;
|
|
||||||
import com.oracle.truffle.api.profiles.LoopConditionProfile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements {@code hash_code} functionality.
|
* Implements {@code hash_code} functionality.
|
||||||
*
|
*
|
||||||
@ -75,10 +73,10 @@ import com.oracle.truffle.api.profiles.LoopConditionProfile;
|
|||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Comparable",
|
type = "Comparable",
|
||||||
name = "hash_builtin",
|
name = "hash_builtin",
|
||||||
description = """
|
description =
|
||||||
Returns hash code of this atom. Use only for overriding default Comparator.
|
|
||||||
"""
|
"""
|
||||||
)
|
Returns hash code of this atom. Use only for overriding default Comparator.
|
||||||
|
""")
|
||||||
public abstract class HashCodeNode extends Node {
|
public abstract class HashCodeNode extends Node {
|
||||||
|
|
||||||
public static HashCodeNode build() {
|
public static HashCodeNode build() {
|
||||||
@ -149,7 +147,8 @@ public abstract class HashCodeNode extends Node {
|
|||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
long hashCodeForUnresolvedSymbol(UnresolvedSymbol unresolvedSymbol,
|
long hashCodeForUnresolvedSymbol(
|
||||||
|
UnresolvedSymbol unresolvedSymbol,
|
||||||
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
||||||
long nameHash = hashCodeNode.execute(unresolvedSymbol.getName());
|
long nameHash = hashCodeNode.execute(unresolvedSymbol.getName());
|
||||||
long scopeHash = hashCodeNode.execute(unresolvedSymbol.getScope());
|
long scopeHash = hashCodeNode.execute(unresolvedSymbol.getScope());
|
||||||
@ -157,39 +156,39 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
long hashCodeForUnresolvedConversion(UnresolvedConversion unresolvedConversion,
|
long hashCodeForUnresolvedConversion(
|
||||||
|
UnresolvedConversion unresolvedConversion,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
return hashCodeForModuleScope(unresolvedConversion.getScope(), interop);
|
return hashCodeForModuleScope(unresolvedConversion.getScope(), interop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
long hashCodeForModuleScope(ModuleScope moduleScope,
|
long hashCodeForModuleScope(
|
||||||
|
ModuleScope moduleScope,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
return hashCodeForModule(moduleScope.getModule(), interop);
|
return hashCodeForModule(moduleScope.getModule(), interop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
long hashCodeForModule(Module module,
|
long hashCodeForModule(
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
Module module, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
return hashCodeForString(module.toString(), interop);
|
return hashCodeForString(module.toString(), interop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
long hashCodeForFile(EnsoFile file,
|
long hashCodeForFile(
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
EnsoFile file, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
return hashCodeForString(file.getPath(), interop);
|
return hashCodeForString(file.getPath(), interop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There is no specialization for {@link TypesLibrary#hasType(Object)}, because also
|
* There is no specialization for {@link TypesLibrary#hasType(Object)}, because also primitive
|
||||||
* primitive values would fall into that specialization and it would be too complicated
|
* values would fall into that specialization and it would be too complicated to make that
|
||||||
* to make that specialization disjunctive. So we rather specialize directly for
|
* specialization disjunctive. So we rather specialize directly for {@link Type}.
|
||||||
* {@link Type}.
|
|
||||||
*/
|
*/
|
||||||
@Specialization
|
@Specialization
|
||||||
long hashCodeForType(Type type,
|
long hashCodeForType(Type type, @Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
||||||
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
|
||||||
if (EnsoContext.get(this).getNothing() == type) {
|
if (EnsoContext.get(this).getNothing() == type) {
|
||||||
// Nothing should be equal to `null`
|
// Nothing should be equal to `null`
|
||||||
return 0;
|
return 0;
|
||||||
@ -205,10 +204,12 @@ public abstract class HashCodeNode extends Node {
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"atomCtorCached == atom.getConstructor()",
|
guards = {
|
||||||
"customComparatorNode.execute(atom) == null",
|
"atomCtorCached == atom.getConstructor()",
|
||||||
}, limit = "5")
|
"customComparatorNode.execute(atom) == null",
|
||||||
|
},
|
||||||
|
limit = "5")
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
long hashCodeForAtomWithDefaultComparator(
|
long hashCodeForAtomWithDefaultComparator(
|
||||||
Atom atom,
|
Atom atom,
|
||||||
@ -247,12 +248,8 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(
|
@Specialization(
|
||||||
guards = {
|
guards = {"atomCtorCached == atom.getConstructor()", "cachedComparator != null"},
|
||||||
"atomCtorCached == atom.getConstructor()",
|
limit = "5")
|
||||||
"cachedComparator != null"
|
|
||||||
},
|
|
||||||
limit = "5"
|
|
||||||
)
|
|
||||||
long hashCodeForAtomWithCustomComparator(
|
long hashCodeForAtomWithCustomComparator(
|
||||||
Atom atom,
|
Atom atom,
|
||||||
@Cached("atom.getConstructor()") AtomConstructor atomCtorCached,
|
@Cached("atom.getConstructor()") AtomConstructor atomCtorCached,
|
||||||
@ -260,11 +257,10 @@ public abstract class HashCodeNode extends Node {
|
|||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
@Cached(value = "customComparatorNode.execute(atom)") Type cachedComparator,
|
@Cached(value = "customComparatorNode.execute(atom)") Type cachedComparator,
|
||||||
@Cached(value = "findHashMethod(cachedComparator)", allowUncached = true)
|
@Cached(value = "findHashMethod(cachedComparator)", allowUncached = true)
|
||||||
Function compareMethod,
|
Function compareMethod,
|
||||||
@Cached(value = "createInvokeNode(compareMethod)") InvokeFunctionNode invokeFunctionNode
|
@Cached(value = "createInvokeNode(compareMethod)") InvokeFunctionNode invokeFunctionNode) {
|
||||||
) {
|
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var args = new Object[] { cachedComparator, atom};
|
var args = new Object[] {cachedComparator, atom};
|
||||||
var result = invokeFunctionNode.execute(compareMethod, null, State.create(ctx), args);
|
var result = invokeFunctionNode.execute(compareMethod, null, State.create(ctx), args);
|
||||||
if (!interop.isNumber(result)) {
|
if (!interop.isNumber(result)) {
|
||||||
throw ctx.raiseAssertionPanic(this, "Custom comparator must return a number", null);
|
throw ctx.raiseAssertionPanic(this, "Custom comparator must return a number", null);
|
||||||
@ -298,7 +294,8 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@Specialization(replaces = {"hashCodeForAtomWithDefaultComparator", "hashCodeForAtomWithCustomComparator"})
|
@Specialization(
|
||||||
|
replaces = {"hashCodeForAtomWithDefaultComparator", "hashCodeForAtomWithCustomComparator"})
|
||||||
long hashCodeForAtomUncached(Atom atom) {
|
long hashCodeForAtomUncached(Atom atom) {
|
||||||
if (atom.getHashCode() != null) {
|
if (atom.getHashCode() != null) {
|
||||||
return atom.getHashCode();
|
return atom.getHashCode();
|
||||||
@ -314,8 +311,7 @@ public abstract class HashCodeNode extends Node {
|
|||||||
InteropLibrary.getFactory().getUncached(),
|
InteropLibrary.getFactory().getUncached(),
|
||||||
customComparator,
|
customComparator,
|
||||||
compareMethod,
|
compareMethod,
|
||||||
createInvokeNode(compareMethod)
|
createInvokeNode(compareMethod));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object[] fields = StructsLibrary.getUncached().getFields(atom);
|
Object[] fields = StructsLibrary.getUncached().getFields(atom);
|
||||||
@ -465,8 +461,7 @@ public abstract class HashCodeNode extends Node {
|
|||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
long hashCodeForText(
|
long hashCodeForText(
|
||||||
Text text,
|
Text text, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
|
||||||
if (text.is_normalized()) {
|
if (text.is_normalized()) {
|
||||||
return text.toString().hashCode();
|
return text.toString().hashCode();
|
||||||
} else {
|
} else {
|
||||||
@ -478,9 +473,7 @@ public abstract class HashCodeNode extends Node {
|
|||||||
@Specialization(
|
@Specialization(
|
||||||
guards = {"interop.isString(selfStr)"},
|
guards = {"interop.isString(selfStr)"},
|
||||||
limit = "3")
|
limit = "3")
|
||||||
long hashCodeForString(
|
long hashCodeForString(Object selfStr, @CachedLibrary("selfStr") InteropLibrary interop) {
|
||||||
Object selfStr,
|
|
||||||
@CachedLibrary("selfStr") InteropLibrary interop) {
|
|
||||||
String str;
|
String str;
|
||||||
try {
|
try {
|
||||||
str = interop.asString(selfStr);
|
str = interop.asString(selfStr);
|
||||||
@ -491,10 +484,7 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(
|
@Specialization(
|
||||||
guards = {
|
guards = {"interop.hasArrayElements(selfArray)", "!interop.hasHashEntries(selfArray)"},
|
||||||
"interop.hasArrayElements(selfArray)",
|
|
||||||
"!interop.hasHashEntries(selfArray)"
|
|
||||||
},
|
|
||||||
limit = "3")
|
limit = "3")
|
||||||
long hashCodeForArray(
|
long hashCodeForArray(
|
||||||
Object selfArray,
|
Object selfArray,
|
||||||
@ -527,10 +517,11 @@ public abstract class HashCodeNode extends Node {
|
|||||||
* Two maps are considered equal, if they have the same entries. Note that we do not care about
|
* Two maps are considered equal, if they have the same entries. Note that we do not care about
|
||||||
* ordering.
|
* ordering.
|
||||||
*/
|
*/
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"interop.hasHashEntries(selfMap)",
|
guards = {
|
||||||
"!interop.hasArrayElements(selfMap)",
|
"interop.hasHashEntries(selfMap)",
|
||||||
})
|
"!interop.hasArrayElements(selfMap)",
|
||||||
|
})
|
||||||
long hashCodeForMap(
|
long hashCodeForMap(
|
||||||
Object selfMap,
|
Object selfMap,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
@ -555,17 +546,19 @@ public abstract class HashCodeNode extends Node {
|
|||||||
return Arrays.hashCode(new long[] {keysHashCode, valuesHashCode, mapSize});
|
return Arrays.hashCode(new long[] {keysHashCode, valuesHashCode, mapSize});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"!isAtom(objectWithMembers)",
|
guards = {
|
||||||
"!isJavaObject(objectWithMembers)",
|
"!isAtom(objectWithMembers)",
|
||||||
"interop.hasMembers(objectWithMembers)",
|
"!isJavaObject(objectWithMembers)",
|
||||||
"!interop.hasArrayElements(objectWithMembers)",
|
"interop.hasMembers(objectWithMembers)",
|
||||||
"!interop.isTime(objectWithMembers)",
|
"!interop.hasArrayElements(objectWithMembers)",
|
||||||
"!interop.isDate(objectWithMembers)",
|
"!interop.isTime(objectWithMembers)",
|
||||||
"!interop.isTimeZone(objectWithMembers)",
|
"!interop.isDate(objectWithMembers)",
|
||||||
"!typesLib.hasType(objectWithMembers)",
|
"!interop.isTimeZone(objectWithMembers)",
|
||||||
})
|
"!typesLib.hasType(objectWithMembers)",
|
||||||
long hashCodeForInteropObjectWithMembers(Object objectWithMembers,
|
})
|
||||||
|
long hashCodeForInteropObjectWithMembers(
|
||||||
|
Object objectWithMembers,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
@CachedLibrary(limit = "5") TypesLibrary typesLib,
|
@CachedLibrary(limit = "5") TypesLibrary typesLib,
|
||||||
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
||||||
@ -587,12 +580,18 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Arrays.hashCode(hashCodes);
|
return Arrays.hashCode(hashCodes);
|
||||||
} catch (UnsupportedMessageException | InvalidArrayIndexException | UnknownIdentifierException e) {
|
} catch (UnsupportedMessageException
|
||||||
|
| InvalidArrayIndexException
|
||||||
|
| UnknownIdentifierException e) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, String.format("An interop object (%s) has probably wrongly specified interop API"
|
throw EnsoContext.get(this)
|
||||||
+ " for members.", objectWithMembers),
|
.raiseAssertionPanic(
|
||||||
e
|
this,
|
||||||
);
|
String.format(
|
||||||
|
"An interop object (%s) has probably wrongly specified interop API"
|
||||||
|
+ " for members.",
|
||||||
|
objectWithMembers),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,8 +604,7 @@ public abstract class HashCodeNode extends Node {
|
|||||||
|
|
||||||
@Specialization(guards = "isJavaObject(hostObject)")
|
@Specialization(guards = "isJavaObject(hostObject)")
|
||||||
long hashCodeForHostObject(
|
long hashCodeForHostObject(
|
||||||
Object hostObject,
|
Object hostObject, @Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop) {
|
|
||||||
try {
|
try {
|
||||||
Object hashCodeRes = interop.invokeMember(hostObject, "hashCode");
|
Object hashCodeRes = interop.invokeMember(hostObject, "hashCode");
|
||||||
assert interop.fitsInInt(hashCodeRes);
|
assert interop.fitsInInt(hashCodeRes);
|
||||||
@ -620,12 +618,13 @@ public abstract class HashCodeNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every host function has a unique fully qualified name, it is not a lambda.
|
* Every host function has a unique fully qualified name, it is not a lambda. We get the hashcode
|
||||||
* We get the hashcode from the qualified name.
|
* from the qualified name.
|
||||||
*/
|
*/
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@Specialization(guards = "isJavaFunction(hostFunction)")
|
@Specialization(guards = "isJavaFunction(hostFunction)")
|
||||||
long hashCodeForHostFunction(Object hostFunction,
|
long hashCodeForHostFunction(
|
||||||
|
Object hostFunction,
|
||||||
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
|
||||||
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
@Shared("hashCodeNode") @Cached HashCodeNode hashCodeNode) {
|
||||||
return hashCodeNode.execute(interop.toDisplayString(hostFunction));
|
return hashCodeNode.execute(interop.toDisplayString(hostFunction));
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.meta;
|
package org.enso.interpreter.node.expression.builtin.meta;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.RootCallTarget;
|
||||||
|
import com.oracle.truffle.api.instrumentation.EventBinding;
|
||||||
|
import com.oracle.truffle.api.interop.InteropException;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
import org.enso.interpreter.instrument.Timer;
|
import org.enso.interpreter.instrument.Timer;
|
||||||
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
|
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode;
|
||||||
@ -9,12 +14,6 @@ import org.enso.interpreter.runtime.data.EnsoObject;
|
|||||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||||
import org.enso.polyglot.debugger.IdExecutionService;
|
import org.enso.polyglot.debugger.IdExecutionService;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.RootCallTarget;
|
|
||||||
import com.oracle.truffle.api.instrumentation.EventBinding;
|
|
||||||
import com.oracle.truffle.api.interop.InteropException;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
|
|
||||||
final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
||||||
|
|
||||||
private final IdExecutionService service;
|
private final IdExecutionService service;
|
||||||
@ -37,7 +36,13 @@ final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
|||||||
this.handle = null;
|
this.handle = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instrumentor(Instrumentor orig, Object onEnter, Object onReturn, Object onReturnExpr, Object onCall, boolean activate) {
|
Instrumentor(
|
||||||
|
Instrumentor orig,
|
||||||
|
Object onEnter,
|
||||||
|
Object onReturn,
|
||||||
|
Object onReturnExpr,
|
||||||
|
Object onCall,
|
||||||
|
boolean activate) {
|
||||||
this.module = orig.module;
|
this.module = orig.module;
|
||||||
this.service = orig.service;
|
this.service = orig.service;
|
||||||
this.target = orig.target;
|
this.target = orig.target;
|
||||||
@ -45,9 +50,7 @@ final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
|||||||
this.onReturn = onReturn != null ? onReturn : orig.onReturn;
|
this.onReturn = onReturn != null ? onReturn : orig.onReturn;
|
||||||
this.onReturnExpr = onReturnExpr != null ? onReturnExpr : orig.onReturnExpr;
|
this.onReturnExpr = onReturnExpr != null ? onReturnExpr : orig.onReturnExpr;
|
||||||
this.onCall = onCall != null ? onCall : orig.onCall;
|
this.onCall = onCall != null ? onCall : orig.onCall;
|
||||||
this.handle = !activate ? null : service.bind(
|
this.handle = !activate ? null : service.bind(module, target, this, new Timer.Disabled());
|
||||||
module, target, this, new Timer.Disabled()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
@ -67,7 +70,8 @@ final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
|||||||
if (onEnter != null) {
|
if (onEnter != null) {
|
||||||
var ret = InteropLibrary.getUncached().execute(onEnter, info.getId().toString());
|
var ret = InteropLibrary.getUncached().execute(onEnter, info.getId().toString());
|
||||||
ret = InteropLibrary.getUncached().isNull(ret) ? null : ret;
|
ret = InteropLibrary.getUncached().isNull(ret) ? null : ret;
|
||||||
return handle.isDisposed() ? null : ret; }
|
return handle.isDisposed() ? null : ret;
|
||||||
|
}
|
||||||
} catch (InteropException ignored) {
|
} catch (InteropException ignored) {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -78,10 +82,11 @@ final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
|||||||
try {
|
try {
|
||||||
if (onReturn != null) {
|
if (onReturn != null) {
|
||||||
var iop = InteropLibrary.getUncached();
|
var iop = InteropLibrary.getUncached();
|
||||||
var result = onReturnExpr == null || !iop.isString(onReturnExpr) ?
|
var result =
|
||||||
info.getResult()
|
onReturnExpr == null || !iop.isString(onReturnExpr)
|
||||||
:
|
? info.getResult()
|
||||||
InstrumentorEvalNode.asSuspendedEval(EnsoLanguage.get(target.getRootNode()), onReturnExpr, info);
|
: InstrumentorEvalNode.asSuspendedEval(
|
||||||
|
EnsoLanguage.get(target.getRootNode()), onReturnExpr, info);
|
||||||
iop.execute(onReturn, info.getId().toString(), result);
|
iop.execute(onReturn, info.getId().toString(), result);
|
||||||
}
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
@ -101,12 +106,13 @@ final class Instrumentor implements EnsoObject, IdExecutionService.Callbacks {
|
|||||||
args[i] = EnsoContext.get(null).getBuiltins().nothing();
|
args[i] = EnsoContext.get(null).getBuiltins().nothing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ret = InteropLibrary.getUncached().execute(
|
var ret =
|
||||||
onCall,
|
InteropLibrary.getUncached()
|
||||||
info.getId().toString(),
|
.execute(
|
||||||
call.getFunction(),
|
onCall,
|
||||||
ArrayLikeHelpers.asVectorWithCheckAt(args)
|
info.getId().toString(),
|
||||||
);
|
call.getFunction(),
|
||||||
|
ArrayLikeHelpers.asVectorWithCheckAt(args));
|
||||||
ret = InteropLibrary.getUncached().isNull(ret) ? null : ret;
|
ret = InteropLibrary.getUncached().isNull(ret) ? null : ret;
|
||||||
return handle.isDisposed() ? null : ret;
|
return handle.isDisposed() ? null : ret;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.meta;
|
package org.enso.interpreter.node.expression.builtin.meta;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||||
@ -10,18 +12,13 @@ import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
|
|||||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Meta",
|
type = "Meta",
|
||||||
name = "instrumentor_builtin",
|
name = "instrumentor_builtin",
|
||||||
description = "Handles instrumentation operations.",
|
description = "Handles instrumentation operations.",
|
||||||
autoRegister = false)
|
autoRegister = false)
|
||||||
public class InstrumentorBuiltin extends Node {
|
public class InstrumentorBuiltin extends Node {
|
||||||
@Child
|
@Child private ArrayLikeAtNode atNode = ArrayLikeAtNode.create();
|
||||||
private ArrayLikeAtNode atNode = ArrayLikeAtNode.create();
|
|
||||||
|
|
||||||
Object execute(Text operation, Object args) {
|
Object execute(Text operation, Object args) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
@ -29,14 +26,15 @@ public class InstrumentorBuiltin extends Node {
|
|||||||
try {
|
try {
|
||||||
Object ret = "newBuilder".equals(op) ? newBuilder(ctx, atNode.executeAt(args, 0)) : null;
|
Object ret = "newBuilder".equals(op) ? newBuilder(ctx, atNode.executeAt(args, 0)) : null;
|
||||||
if (atNode.executeAt(args, 0) instanceof Instrumentor b) {
|
if (atNode.executeAt(args, 0) instanceof Instrumentor b) {
|
||||||
ret = switch (op) {
|
ret =
|
||||||
case "onEnter" -> onEnter(b, atNode.executeAt(args, 1));
|
switch (op) {
|
||||||
case "onReturn" -> onReturn(b, atNode.executeAt(args, 1), atNode.executeAt(args, 2));
|
case "onEnter" -> onEnter(b, atNode.executeAt(args, 1));
|
||||||
case "onCall" -> onCall(b, atNode.executeAt(args, 1));
|
case "onReturn" -> onReturn(b, atNode.executeAt(args, 1), atNode.executeAt(args, 2));
|
||||||
case "activate" -> activate(b, atNode.executeAt(args, 1));
|
case "onCall" -> onCall(b, atNode.executeAt(args, 1));
|
||||||
case "deactivate" -> b.deactivate();
|
case "activate" -> activate(b, atNode.executeAt(args, 1));
|
||||||
default -> null;
|
case "deactivate" -> b.deactivate();
|
||||||
};
|
default -> null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (ret == null) {
|
if (ret == null) {
|
||||||
var err = ctx.getBuiltins().error().makeUnimplemented(operation.toString());
|
var err = ctx.getBuiltins().error().makeUnimplemented(operation.toString());
|
||||||
@ -58,7 +56,8 @@ public class InstrumentorBuiltin extends Node {
|
|||||||
if (fnAndType != null) {
|
if (fnAndType != null) {
|
||||||
var service = ctx.getIdValueExtractor();
|
var service = ctx.getIdValueExtractor();
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
return new Instrumentor(symbol.getScope().getModule(), service, fnAndType.getLeft().getCallTarget());
|
return new Instrumentor(
|
||||||
|
symbol.getScope().getModule(), service, fnAndType.getLeft().getCallTarget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,14 @@ import org.enso.interpreter.runtime.data.text.Text;
|
|||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
import org.enso.interpreter.runtime.error.DataflowError;
|
||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
|
|
||||||
@BuiltinMethod(type = "Integer", name = "parse", description = """
|
@BuiltinMethod(
|
||||||
Parse integer number""", autoRegister = false)
|
type = "Integer",
|
||||||
|
name = "parse",
|
||||||
|
description = """
|
||||||
|
Parse integer number""",
|
||||||
|
autoRegister = false)
|
||||||
public final class ParseIntegerNode extends IntegerNode {
|
public final class ParseIntegerNode extends IntegerNode {
|
||||||
@Child
|
@Child ToJavaStringNode toJavaString = ToJavaStringNode.build();
|
||||||
ToJavaStringNode toJavaString = ToJavaStringNode.build();
|
|
||||||
private final BranchProfile noEx1 = BranchProfile.create();
|
private final BranchProfile noEx1 = BranchProfile.create();
|
||||||
private final BranchProfile noEx2 = BranchProfile.create();
|
private final BranchProfile noEx2 = BranchProfile.create();
|
||||||
|
|
||||||
@ -37,4 +40,3 @@ public final class ParseIntegerNode extends IntegerNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ public class ToEnsoNumberNode extends Node {
|
|||||||
this.fitsProfile = fitsProfile;
|
this.fitsProfile = fitsProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return a new instance of this node. */
|
/**
|
||||||
|
* @return a new instance of this node.
|
||||||
|
*/
|
||||||
@NeverDefault
|
@NeverDefault
|
||||||
public static ToEnsoNumberNode create() {
|
public static ToEnsoNumberNode create() {
|
||||||
return new ToEnsoNumberNode(CountingConditionProfile.create());
|
return new ToEnsoNumberNode(CountingConditionProfile.create());
|
||||||
|
@ -28,25 +28,30 @@ public abstract class CustomComparatorNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the given atom's comparator if it is a comparator that is different
|
* Returns the given atom's comparator if it is a comparator that is different than the default
|
||||||
* than the default (internal) one.
|
* (internal) one.
|
||||||
*
|
*
|
||||||
* @param atom Atom for which we check whether it has custom comparator
|
* @param atom Atom for which we check whether it has custom comparator
|
||||||
* @return {@code null} if the atom has default comparator. Otherwise it returns the real comparator type.
|
* @return {@code null} if the atom has default comparator. Otherwise it returns the real
|
||||||
|
* comparator type.
|
||||||
*/
|
*/
|
||||||
public abstract Type execute(Atom atom);
|
public abstract Type execute(Atom atom);
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
Type hasCustomComparatorCached(
|
Type hasCustomComparatorCached(
|
||||||
Atom atom,
|
Atom atom,
|
||||||
@Cached(value = "buildConvertionNode()", allowUncached = true) InvokeConversionNode convertNode,
|
@Cached(value = "buildConvertionNode()", allowUncached = true)
|
||||||
@Cached(value = "createConversion()", allowUncached = true) UnresolvedConversion conversion
|
InvokeConversionNode convertNode,
|
||||||
) {
|
@Cached(value = "createConversion()", allowUncached = true) UnresolvedConversion conversion) {
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var comparableType = ctx.getBuiltins().comparable().getType();
|
var comparableType = ctx.getBuiltins().comparable().getType();
|
||||||
var state = State.create(ctx);
|
var state = State.create(ctx);
|
||||||
Object res = convertNode.execute(null, state, conversion, comparableType, atom, new Object[] { comparableType, atom });
|
Object res =
|
||||||
return res instanceof Type result && result != ctx.getBuiltins().defaultComparator().getType() ? result : null;
|
convertNode.execute(
|
||||||
|
null, state, conversion, comparableType, atom, new Object[] {comparableType, atom});
|
||||||
|
return res instanceof Type result && result != ctx.getBuiltins().defaultComparator().getType()
|
||||||
|
? result
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NeverDefault
|
@NeverDefault
|
||||||
@ -61,6 +66,7 @@ public abstract class CustomComparatorNode extends Node {
|
|||||||
CallArgumentInfo[] argSchema = new CallArgumentInfo[2];
|
CallArgumentInfo[] argSchema = new CallArgumentInfo[2];
|
||||||
argSchema[0] = new CallArgumentInfo();
|
argSchema[0] = new CallArgumentInfo();
|
||||||
argSchema[1] = new CallArgumentInfo();
|
argSchema[1] = new CallArgumentInfo();
|
||||||
return InvokeConversionNode.build(argSchema, DefaultsExecutionMode.EXECUTE, ArgumentsExecutionMode.EXECUTE, 1);
|
return InvokeConversionNode.build(
|
||||||
|
argSchema, DefaultsExecutionMode.EXECUTE, ArgumentsExecutionMode.EXECUTE, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,21 +16,19 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import org.enso.interpreter.dsl.AcceptsError;
|
import org.enso.interpreter.dsl.AcceptsError;
|
||||||
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.EnsoContext;
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.DataflowError;
|
|
||||||
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
import org.enso.interpreter.runtime.error.WarningsLibrary;
|
||||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||||
|
|
||||||
@BuiltinMethod(
|
@BuiltinMethod(
|
||||||
type = "Comparable",
|
type = "Comparable",
|
||||||
name = "less_than_builtin",
|
name = "less_than_builtin",
|
||||||
description = """
|
description =
|
||||||
|
"""
|
||||||
Returns true if self is less than `other`. Or return Nothing if the values are
|
Returns true if self is less than `other`. Or return Nothing if the values are
|
||||||
not comparable.
|
not comparable.
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
@GenerateUncached
|
@GenerateUncached
|
||||||
public abstract class LessThanNode extends Node {
|
public abstract class LessThanNode extends Node {
|
||||||
|
|
||||||
@ -126,23 +124,27 @@ public abstract class LessThanNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If one of the objects has warnings attached, just treat it as an object without any
|
* If one of the objects has warnings attached, just treat it as an object without any warnings.
|
||||||
* warnings.
|
|
||||||
*/
|
*/
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfWarnLib.hasWarnings(selfWithWarnings) || otherWarnLib.hasWarnings(otherWithWarnings)"
|
guards = {
|
||||||
}, limit = "3")
|
"selfWarnLib.hasWarnings(selfWithWarnings) || otherWarnLib.hasWarnings(otherWithWarnings)"
|
||||||
Object lessWithWarnings(Object selfWithWarnings, Object otherWithWarnings,
|
},
|
||||||
|
limit = "3")
|
||||||
|
Object lessWithWarnings(
|
||||||
|
Object selfWithWarnings,
|
||||||
|
Object otherWithWarnings,
|
||||||
@CachedLibrary("selfWithWarnings") WarningsLibrary selfWarnLib,
|
@CachedLibrary("selfWithWarnings") WarningsLibrary selfWarnLib,
|
||||||
@CachedLibrary("otherWithWarnings") WarningsLibrary otherWarnLib,
|
@CachedLibrary("otherWithWarnings") WarningsLibrary otherWarnLib,
|
||||||
@Cached LessThanNode lessThanNode
|
@Cached LessThanNode lessThanNode) {
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
Object self =
|
Object self =
|
||||||
selfWarnLib.hasWarnings(selfWithWarnings) ? selfWarnLib.removeWarnings(selfWithWarnings)
|
selfWarnLib.hasWarnings(selfWithWarnings)
|
||||||
|
? selfWarnLib.removeWarnings(selfWithWarnings)
|
||||||
: selfWithWarnings;
|
: selfWithWarnings;
|
||||||
Object other =
|
Object other =
|
||||||
otherWarnLib.hasWarnings(otherWithWarnings) ? otherWarnLib.removeWarnings(otherWithWarnings)
|
otherWarnLib.hasWarnings(otherWithWarnings)
|
||||||
|
? otherWarnLib.removeWarnings(otherWithWarnings)
|
||||||
: otherWithWarnings;
|
: otherWithWarnings;
|
||||||
return lessThanNode.execute(self, other);
|
return lessThanNode.execute(self, other);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
@ -151,7 +153,9 @@ public abstract class LessThanNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(limit = "3")
|
@Specialization(limit = "3")
|
||||||
boolean lessTexts(Text selfText, Text otherText,
|
boolean lessTexts(
|
||||||
|
Text selfText,
|
||||||
|
Text otherText,
|
||||||
@CachedLibrary("selfText") InteropLibrary selfInterop,
|
@CachedLibrary("selfText") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherText") InteropLibrary otherInterop) {
|
@CachedLibrary("otherText") InteropLibrary otherInterop) {
|
||||||
if (selfText.is_normalized() && otherText.is_normalized()) {
|
if (selfText.is_normalized() && otherText.is_normalized()) {
|
||||||
@ -162,14 +166,12 @@ public abstract class LessThanNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(
|
@Specialization(
|
||||||
guards = {
|
guards = {"selfInterop.isString(selfStr)", "otherInterop.isString(otherStr)"},
|
||||||
"selfInterop.isString(selfStr)",
|
limit = "5")
|
||||||
"otherInterop.isString(otherStr)"
|
|
||||||
},
|
|
||||||
limit = "5"
|
|
||||||
)
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
boolean lessInteropStrings(Object selfStr, Object otherStr,
|
boolean lessInteropStrings(
|
||||||
|
Object selfStr,
|
||||||
|
Object otherStr,
|
||||||
@CachedLibrary("selfStr") InteropLibrary selfInterop,
|
@CachedLibrary("selfStr") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherStr") InteropLibrary otherInterop) {
|
@CachedLibrary("otherStr") InteropLibrary otherInterop) {
|
||||||
String selfJavaString;
|
String selfJavaString;
|
||||||
@ -180,23 +182,17 @@ public abstract class LessThanNode extends Node {
|
|||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
}
|
}
|
||||||
return Normalizer.compare(
|
return Normalizer.compare(selfJavaString, otherJavaString, Normalizer.FOLD_CASE_DEFAULT) < 0;
|
||||||
selfJavaString,
|
|
||||||
otherJavaString,
|
|
||||||
Normalizer.FOLD_CASE_DEFAULT
|
|
||||||
) < 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfInterop.isBoolean(selfBoolean)",
|
guards = {"selfInterop.isBoolean(selfBoolean)", "otherInterop.isBoolean(otherBoolean)"},
|
||||||
"otherInterop.isBoolean(otherBoolean)"
|
limit = "3")
|
||||||
}, limit = "3")
|
|
||||||
boolean lessInteropBoolean(
|
boolean lessInteropBoolean(
|
||||||
Object selfBoolean,
|
Object selfBoolean,
|
||||||
Object otherBoolean,
|
Object otherBoolean,
|
||||||
@CachedLibrary("selfBoolean") InteropLibrary selfInterop,
|
@CachedLibrary("selfBoolean") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherBoolean") InteropLibrary otherInterop
|
@CachedLibrary("otherBoolean") InteropLibrary otherInterop) {
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
return !selfInterop.asBoolean(selfBoolean) && otherInterop.asBoolean(otherBoolean);
|
return !selfInterop.asBoolean(selfBoolean) && otherInterop.asBoolean(otherBoolean);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
@ -205,105 +201,114 @@ public abstract class LessThanNode extends Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfInterop.isDate(selfZonedDateTime)",
|
guards = {
|
||||||
"selfInterop.isTime(selfZonedDateTime)",
|
"selfInterop.isDate(selfZonedDateTime)",
|
||||||
"selfInterop.isTimeZone(selfZonedDateTime)",
|
"selfInterop.isTime(selfZonedDateTime)",
|
||||||
"otherInterop.isDate(otherZonedDateTime)",
|
"selfInterop.isTimeZone(selfZonedDateTime)",
|
||||||
"otherInterop.isTime(otherZonedDateTime)",
|
"otherInterop.isDate(otherZonedDateTime)",
|
||||||
"otherInterop.isTimeZone(otherZonedDateTime)"
|
"otherInterop.isTime(otherZonedDateTime)",
|
||||||
}, limit = "3")
|
"otherInterop.isTimeZone(otherZonedDateTime)"
|
||||||
boolean lessInteropZonedDateTimes(Object selfZonedDateTime, Object otherZonedDateTime,
|
},
|
||||||
|
limit = "3")
|
||||||
|
boolean lessInteropZonedDateTimes(
|
||||||
|
Object selfZonedDateTime,
|
||||||
|
Object otherZonedDateTime,
|
||||||
@CachedLibrary("selfZonedDateTime") InteropLibrary selfInterop,
|
@CachedLibrary("selfZonedDateTime") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherZonedDateTime") InteropLibrary otherInterop) {
|
@CachedLibrary("otherZonedDateTime") InteropLibrary otherInterop) {
|
||||||
try {
|
try {
|
||||||
var self = ZonedDateTime.of(
|
var self =
|
||||||
selfInterop.asDate(selfZonedDateTime),
|
ZonedDateTime.of(
|
||||||
selfInterop.asTime(selfZonedDateTime),
|
selfInterop.asDate(selfZonedDateTime),
|
||||||
selfInterop.asTimeZone(selfZonedDateTime)
|
selfInterop.asTime(selfZonedDateTime),
|
||||||
);
|
selfInterop.asTimeZone(selfZonedDateTime));
|
||||||
var other = ZonedDateTime.of(
|
var other =
|
||||||
otherInterop.asDate(otherZonedDateTime),
|
ZonedDateTime.of(
|
||||||
otherInterop.asTime(otherZonedDateTime),
|
otherInterop.asDate(otherZonedDateTime),
|
||||||
otherInterop.asTimeZone(otherZonedDateTime)
|
otherInterop.asTime(otherZonedDateTime),
|
||||||
);
|
otherInterop.asTimeZone(otherZonedDateTime));
|
||||||
return self.compareTo(other) < 0;
|
return self.compareTo(other) < 0;
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfInterop.isDate(selfDateTime)",
|
guards = {
|
||||||
"selfInterop.isTime(selfDateTime)",
|
"selfInterop.isDate(selfDateTime)",
|
||||||
"!selfInterop.isTimeZone(selfDateTime)",
|
"selfInterop.isTime(selfDateTime)",
|
||||||
"otherInterop.isDate(otherDateTime)",
|
"!selfInterop.isTimeZone(selfDateTime)",
|
||||||
"otherInterop.isTime(otherDateTime)",
|
"otherInterop.isDate(otherDateTime)",
|
||||||
"!otherInterop.isTimeZone(otherDateTime)"
|
"otherInterop.isTime(otherDateTime)",
|
||||||
}, limit = "3")
|
"!otherInterop.isTimeZone(otherDateTime)"
|
||||||
boolean lessInteropDateTimes(Object selfDateTime, Object otherDateTime,
|
},
|
||||||
|
limit = "3")
|
||||||
|
boolean lessInteropDateTimes(
|
||||||
|
Object selfDateTime,
|
||||||
|
Object otherDateTime,
|
||||||
@CachedLibrary("selfDateTime") InteropLibrary selfInterop,
|
@CachedLibrary("selfDateTime") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherDateTime") InteropLibrary otherInterop) {
|
@CachedLibrary("otherDateTime") InteropLibrary otherInterop) {
|
||||||
try {
|
try {
|
||||||
var self = LocalDateTime.of(
|
var self =
|
||||||
selfInterop.asDate(selfDateTime),
|
LocalDateTime.of(selfInterop.asDate(selfDateTime), selfInterop.asTime(selfDateTime));
|
||||||
selfInterop.asTime(selfDateTime)
|
var other =
|
||||||
);
|
LocalDateTime.of(otherInterop.asDate(otherDateTime), otherInterop.asTime(otherDateTime));
|
||||||
var other = LocalDateTime.of(
|
|
||||||
otherInterop.asDate(otherDateTime),
|
|
||||||
otherInterop.asTime(otherDateTime)
|
|
||||||
);
|
|
||||||
return self.isBefore(other);
|
return self.isBefore(other);
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfInterop.isDate(selfDate)",
|
guards = {
|
||||||
"!selfInterop.isTime(selfDate)",
|
"selfInterop.isDate(selfDate)",
|
||||||
"!selfInterop.isTimeZone(selfDate)",
|
"!selfInterop.isTime(selfDate)",
|
||||||
"otherInterop.isDate(otherDate)",
|
"!selfInterop.isTimeZone(selfDate)",
|
||||||
"!otherInterop.isTime(otherDate)",
|
"otherInterop.isDate(otherDate)",
|
||||||
"!otherInterop.isTimeZone(otherDate)"
|
"!otherInterop.isTime(otherDate)",
|
||||||
}, limit = "3")
|
"!otherInterop.isTimeZone(otherDate)"
|
||||||
boolean lessInteropDates(Object selfDate, Object otherDate,
|
},
|
||||||
|
limit = "3")
|
||||||
|
boolean lessInteropDates(
|
||||||
|
Object selfDate,
|
||||||
|
Object otherDate,
|
||||||
@CachedLibrary("selfDate") InteropLibrary selfInterop,
|
@CachedLibrary("selfDate") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherDate") InteropLibrary otherInterop) {
|
@CachedLibrary("otherDate") InteropLibrary otherInterop) {
|
||||||
try {
|
try {
|
||||||
return selfInterop.asDate(selfDate).isBefore(
|
return selfInterop.asDate(selfDate).isBefore(otherInterop.asDate(otherDate));
|
||||||
otherInterop.asDate(otherDate)
|
|
||||||
);
|
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"!selfInterop.isDate(selfTime)",
|
guards = {
|
||||||
"selfInterop.isTime(selfTime)",
|
"!selfInterop.isDate(selfTime)",
|
||||||
"!selfInterop.isTimeZone(selfTime)",
|
"selfInterop.isTime(selfTime)",
|
||||||
"!otherInterop.isDate(otherTime)",
|
"!selfInterop.isTimeZone(selfTime)",
|
||||||
"otherInterop.isTime(otherTime)",
|
"!otherInterop.isDate(otherTime)",
|
||||||
"!otherInterop.isTimeZone(otherTime)"
|
"otherInterop.isTime(otherTime)",
|
||||||
}, limit = "3")
|
"!otherInterop.isTimeZone(otherTime)"
|
||||||
boolean lessInteropTimes(Object selfTime, Object otherTime,
|
},
|
||||||
|
limit = "3")
|
||||||
|
boolean lessInteropTimes(
|
||||||
|
Object selfTime,
|
||||||
|
Object otherTime,
|
||||||
@CachedLibrary("selfTime") InteropLibrary selfInterop,
|
@CachedLibrary("selfTime") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherTime") InteropLibrary otherInterop) {
|
@CachedLibrary("otherTime") InteropLibrary otherInterop) {
|
||||||
try {
|
try {
|
||||||
return selfInterop.asTime(selfTime).isBefore(
|
return selfInterop.asTime(selfTime).isBefore(otherInterop.asTime(otherTime));
|
||||||
otherInterop.asTime(otherTime)
|
|
||||||
);
|
|
||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {
|
@Specialization(
|
||||||
"selfInterop.isDuration(selfDuration)",
|
guards = {"selfInterop.isDuration(selfDuration)", "otherInterop.isDuration(otherDuration)"},
|
||||||
"otherInterop.isDuration(otherDuration)"
|
limit = "3")
|
||||||
}, limit = "3")
|
boolean lessInteropDuration(
|
||||||
boolean lessInteropDuration(Object selfDuration, Object otherDuration,
|
Object selfDuration,
|
||||||
|
Object otherDuration,
|
||||||
@CachedLibrary("selfDuration") InteropLibrary selfInterop,
|
@CachedLibrary("selfDuration") InteropLibrary selfInterop,
|
||||||
@CachedLibrary("otherDuration") InteropLibrary otherInterop) {
|
@CachedLibrary("otherDuration") InteropLibrary otherInterop) {
|
||||||
try {
|
try {
|
||||||
@ -323,6 +328,4 @@ public abstract class LessThanNode extends Node {
|
|||||||
private Object nothing() {
|
private Object nothing() {
|
||||||
return EnsoContext.get(this).getNothing();
|
return EnsoContext.get(this).getNothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,32 +29,44 @@ public class Ordering extends Builtin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the Less constructor */
|
/**
|
||||||
|
* @return the Less constructor
|
||||||
|
*/
|
||||||
public AtomConstructor less() {
|
public AtomConstructor less() {
|
||||||
return getConstructors()[0];
|
return getConstructors()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the Equal constructor */
|
/**
|
||||||
|
* @return the Equal constructor
|
||||||
|
*/
|
||||||
public AtomConstructor equal() {
|
public AtomConstructor equal() {
|
||||||
return getConstructors()[1];
|
return getConstructors()[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the Greater constructor */
|
/**
|
||||||
|
* @return the Greater constructor
|
||||||
|
*/
|
||||||
public AtomConstructor greater() {
|
public AtomConstructor greater() {
|
||||||
return getConstructors()[2];
|
return getConstructors()[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return a new instance of Less */
|
/**
|
||||||
|
* @return a new instance of Less
|
||||||
|
*/
|
||||||
public Atom newLess() {
|
public Atom newLess() {
|
||||||
return less().newInstance();
|
return less().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return a new instance of Equal */
|
/**
|
||||||
|
* @return a new instance of Equal
|
||||||
|
*/
|
||||||
public Atom newEqual() {
|
public Atom newEqual() {
|
||||||
return equal().newInstance();
|
return equal().newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return a new instance of Greater */
|
/**
|
||||||
|
* @return a new instance of Greater
|
||||||
|
*/
|
||||||
public Atom newGreater() {
|
public Atom newGreater() {
|
||||||
return greater().newInstance();
|
return greater().newInstance();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.ordering;
|
package org.enso.interpreter.node.expression.builtin.ordering;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached;
|
||||||
|
import com.oracle.truffle.api.dsl.Cached.Shared;
|
||||||
|
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||||
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
|
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||||
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
|
import com.oracle.truffle.api.library.CachedLibrary;
|
||||||
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -9,7 +20,6 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.enso.interpreter.dsl.AcceptsError;
|
import org.enso.interpreter.dsl.AcceptsError;
|
||||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||||
import org.enso.interpreter.node.callable.dispatch.CallOptimiserNode;
|
import org.enso.interpreter.node.callable.dispatch.CallOptimiserNode;
|
||||||
@ -34,18 +44,6 @@ import org.enso.interpreter.runtime.error.WithWarnings;
|
|||||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||||
import org.enso.interpreter.runtime.state.State;
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached;
|
|
||||||
import com.oracle.truffle.api.dsl.Cached.Shared;
|
|
||||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
|
||||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
|
||||||
import com.oracle.truffle.api.library.CachedLibrary;
|
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts a vector with elements that have only Default_Comparator, thus, only elements with a
|
* Sorts a vector with elements that have only Default_Comparator, thus, only elements with a
|
||||||
* builtin type, which is the most common scenario for sorting.
|
* builtin type, which is the most common scenario for sorting.
|
||||||
@ -189,8 +187,7 @@ public abstract class SortVectorNode extends Node {
|
|||||||
var problemBehavior = ProblemBehavior.fromInt((int) problemBehaviorNum);
|
var problemBehavior = ProblemBehavior.fromInt((int) problemBehaviorNum);
|
||||||
// Split into groups
|
// Split into groups
|
||||||
List<Object> elems = readInteropArray(lengthNode, atNode, warningsLib, self);
|
List<Object> elems = readInteropArray(lengthNode, atNode, warningsLib, self);
|
||||||
List<Type> comparators =
|
List<Type> comparators = readInteropArray(lengthNode, atNode, warningsLib, comparatorsArray);
|
||||||
readInteropArray(lengthNode, atNode, warningsLib, comparatorsArray);
|
|
||||||
List<Function> compareFuncs =
|
List<Function> compareFuncs =
|
||||||
readInteropArray(lengthNode, atNode, warningsLib, compareFuncsArray);
|
readInteropArray(lengthNode, atNode, warningsLib, compareFuncsArray);
|
||||||
List<Group> groups = splitByComparators(elems, comparators, compareFuncs);
|
List<Group> groups = splitByComparators(elems, comparators, compareFuncs);
|
||||||
@ -425,7 +422,8 @@ public abstract class SortVectorNode extends Node {
|
|||||||
return 50;
|
return 50;
|
||||||
} else {
|
} else {
|
||||||
// Type is not a builtin type
|
// Type is not a builtin type
|
||||||
throw EnsoContext.get(this).raiseAssertionPanic(this, "Should be a builtin type: " + builtinType, null);
|
throw EnsoContext.get(this)
|
||||||
|
.raiseAssertionPanic(this, "Should be a builtin type: " + builtinType, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,8 +447,7 @@ public abstract class SortVectorNode extends Node {
|
|||||||
|
|
||||||
/** Returns true iff the given array of comparators is all Default_Comparator */
|
/** Returns true iff the given array of comparators is all Default_Comparator */
|
||||||
boolean areAllDefaultComparators(
|
boolean areAllDefaultComparators(
|
||||||
ArrayLikeLengthNode lengthNode, ArrayLikeAtNode atNode, Object comparators
|
ArrayLikeLengthNode lengthNode, ArrayLikeAtNode atNode, Object comparators) {
|
||||||
) {
|
|
||||||
var ctx = EnsoContext.get(this);
|
var ctx = EnsoContext.get(this);
|
||||||
var longSize = 0L;
|
var longSize = 0L;
|
||||||
try {
|
try {
|
||||||
@ -666,9 +663,8 @@ public abstract class SortVectorNode extends Node {
|
|||||||
/**
|
/**
|
||||||
* Helper class that returns the comparator function.
|
* Helper class that returns the comparator function.
|
||||||
*
|
*
|
||||||
* The class is introduced to handle the presence of {@code UnresolvedSymbol},
|
* <p>The class is introduced to handle the presence of {@code UnresolvedSymbol}, as the
|
||||||
* as the comparator function, which has to be first resolved before it
|
* comparator function, which has to be first resolved before it can be used to compare values.
|
||||||
* can be used to compare values.
|
|
||||||
*/
|
*/
|
||||||
private abstract class Compare {
|
private abstract class Compare {
|
||||||
|
|
||||||
@ -687,7 +683,6 @@ public abstract class SortVectorNode extends Node {
|
|||||||
* @return a non-null comparator function.
|
* @return a non-null comparator function.
|
||||||
*/
|
*/
|
||||||
abstract Function get(Object arg);
|
abstract Function get(Object arg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class CompareFromFunction extends Compare {
|
private final class CompareFromFunction extends Compare {
|
||||||
@ -719,21 +714,22 @@ public abstract class SortVectorNode extends Node {
|
|||||||
private final MethodResolverNode methodResolverNode;
|
private final MethodResolverNode methodResolverNode;
|
||||||
private final TypesLibrary typesLibrary;
|
private final TypesLibrary typesLibrary;
|
||||||
|
|
||||||
private CompareFromUnresolvedSymbol(UnresolvedSymbol unresolvedSymbol,
|
private CompareFromUnresolvedSymbol(
|
||||||
MethodResolverNode methodResolvedNode,
|
UnresolvedSymbol unresolvedSymbol,
|
||||||
TypesLibrary typesLibrary) {
|
MethodResolverNode methodResolvedNode,
|
||||||
|
TypesLibrary typesLibrary) {
|
||||||
this.unresolvedSymbol = unresolvedSymbol;
|
this.unresolvedSymbol = unresolvedSymbol;
|
||||||
this.methodResolverNode = methodResolvedNode;
|
this.methodResolverNode = methodResolvedNode;
|
||||||
this.typesLibrary = typesLibrary;
|
this.typesLibrary = typesLibrary;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean hasFunctionSelfArgument(Object definedOn) {
|
boolean hasFunctionSelfArgument(Object definedOn) {
|
||||||
var resolvedFunction = methodResolverNode.expectNonNull(definedOn, typesLibrary.getType(definedOn), unresolvedSymbol);
|
var resolvedFunction =
|
||||||
return resolvedFunction.getSchema().getArgumentsCount() > 0 &&
|
methodResolverNode.expectNonNull(
|
||||||
resolvedFunction.getSchema().getArgumentInfos()[0].getName().equals("self");
|
definedOn, typesLibrary.getType(definedOn), unresolvedSymbol);
|
||||||
|
return resolvedFunction.getSchema().getArgumentsCount() > 0
|
||||||
|
&& resolvedFunction.getSchema().getArgumentInfos()[0].getName().equals("self");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -750,6 +746,7 @@ public abstract class SortVectorNode extends Node {
|
|||||||
private final class GenericSortComparator extends SortComparator {
|
private final class GenericSortComparator extends SortComparator {
|
||||||
|
|
||||||
private final boolean ascending;
|
private final boolean ascending;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either function from `by` parameter to the `Vector.sort` method, or the `compare` function
|
* Either function from `by` parameter to the `Vector.sort` method, or the `compare` function
|
||||||
* extracted from the comparator for the appropriate group.
|
* extracted from the comparator for the appropriate group.
|
||||||
@ -806,8 +803,10 @@ public abstract class SortVectorNode extends Node {
|
|||||||
Object yConverted;
|
Object yConverted;
|
||||||
if (hasCustomOnFunc) {
|
if (hasCustomOnFunc) {
|
||||||
// onFunc cannot have `self` argument, we assume it has just one argument.
|
// onFunc cannot have `self` argument, we assume it has just one argument.
|
||||||
xConverted = callNode.executeDispatch(null, onFunc.get(x), null, state, new Object[]{x}, null);
|
xConverted =
|
||||||
yConverted = callNode.executeDispatch(null, onFunc.get(y), null, state, new Object[]{y}, null);
|
callNode.executeDispatch(null, onFunc.get(x), null, state, new Object[] {x}, null);
|
||||||
|
yConverted =
|
||||||
|
callNode.executeDispatch(null, onFunc.get(y), null, state, new Object[] {y}, null);
|
||||||
} else {
|
} else {
|
||||||
xConverted = x;
|
xConverted = x;
|
||||||
yConverted = y;
|
yConverted = y;
|
||||||
@ -818,7 +817,8 @@ public abstract class SortVectorNode extends Node {
|
|||||||
} else {
|
} else {
|
||||||
args = new Object[] {xConverted, yConverted};
|
args = new Object[] {xConverted, yConverted};
|
||||||
}
|
}
|
||||||
Object res = callNode.executeDispatch(null, compareFunc.get(xConverted), null, state, args, null);
|
Object res =
|
||||||
|
callNode.executeDispatch(null, compareFunc.get(xConverted), null, state, args, null);
|
||||||
if (res == less) {
|
if (res == less) {
|
||||||
return ascending ? -1 : 1;
|
return ascending ? -1 : 1;
|
||||||
} else if (res == equal) {
|
} else if (res == equal) {
|
||||||
@ -839,20 +839,30 @@ public abstract class SortVectorNode extends Node {
|
|||||||
* Checks value given for {@code by} parameter and converts it to {@link Function}. Throw a
|
* Checks value given for {@code by} parameter and converts it to {@link Function}. Throw a
|
||||||
* dataflow error otherwise.
|
* dataflow error otherwise.
|
||||||
*/
|
*/
|
||||||
private Compare checkAndConvertByFunc(Object byFuncObj, TypesLibrary typesLibrary, MethodResolverNode methodResolverNode) {
|
private Compare checkAndConvertByFunc(
|
||||||
|
Object byFuncObj, TypesLibrary typesLibrary, MethodResolverNode methodResolverNode) {
|
||||||
return checkAndConvertFunction(
|
return checkAndConvertFunction(
|
||||||
byFuncObj, "Unsupported argument for `by`, expected a method with two arguments", 2, 3,
|
byFuncObj,
|
||||||
typesLibrary, methodResolverNode);
|
"Unsupported argument for `by`, expected a method with two arguments",
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
typesLibrary,
|
||||||
|
methodResolverNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the value given for {@code on} parameter and converts it to {@link Function}. Throws a
|
* Checks the value given for {@code on} parameter and converts it to {@link Function}. Throws a
|
||||||
* dataflow error otherwise.
|
* dataflow error otherwise.
|
||||||
*/
|
*/
|
||||||
private Compare checkAndConvertOnFunc(Object onFuncObj, TypesLibrary typesLibrary, MethodResolverNode methodResolverNode) {
|
private Compare checkAndConvertOnFunc(
|
||||||
|
Object onFuncObj, TypesLibrary typesLibrary, MethodResolverNode methodResolverNode) {
|
||||||
return checkAndConvertFunction(
|
return checkAndConvertFunction(
|
||||||
onFuncObj, "Unsupported argument for `on`, expected a method with one argument", 1, 1,
|
onFuncObj,
|
||||||
typesLibrary, methodResolverNode);
|
"Unsupported argument for `on`, expected a method with one argument",
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
typesLibrary,
|
||||||
|
methodResolverNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -862,8 +872,12 @@ public abstract class SortVectorNode extends Node {
|
|||||||
* @param typesLibrary types library for resolving the dispatch type for unresolved symbols.
|
* @param typesLibrary types library for resolving the dispatch type for unresolved symbols.
|
||||||
*/
|
*/
|
||||||
private Compare checkAndConvertFunction(
|
private Compare checkAndConvertFunction(
|
||||||
Object funcObj, String errMsg, int minArgCount, int maxArgCount,
|
Object funcObj,
|
||||||
TypesLibrary typesLibrary, MethodResolverNode methodResolverNode) {
|
String errMsg,
|
||||||
|
int minArgCount,
|
||||||
|
int maxArgCount,
|
||||||
|
TypesLibrary typesLibrary,
|
||||||
|
MethodResolverNode methodResolverNode) {
|
||||||
if (funcObj instanceof UnresolvedSymbol unresolved) {
|
if (funcObj instanceof UnresolvedSymbol unresolved) {
|
||||||
return new CompareFromUnresolvedSymbol(unresolved, methodResolverNode, typesLibrary);
|
return new CompareFromUnresolvedSymbol(unresolved, methodResolverNode, typesLibrary);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ import org.enso.interpreter.runtime.state.State;
|
|||||||
type = "Managed_Resource",
|
type = "Managed_Resource",
|
||||||
name = "with",
|
name = "with",
|
||||||
description =
|
description =
|
||||||
"Applies the passed action to the underlying resource managed by the passed Managed_Resource object.")
|
"Applies the passed action to the underlying resource managed by the passed"
|
||||||
|
+ " Managed_Resource object.")
|
||||||
public abstract class WithNode extends Node {
|
public abstract class WithNode extends Node {
|
||||||
|
|
||||||
private @Child InvokeCallableNode invokeCallableNode =
|
private @Child InvokeCallableNode invokeCallableNode =
|
||||||
|
@ -82,8 +82,7 @@ public abstract class AssertNode extends Node {
|
|||||||
} catch (UnsupportedMessageException e) {
|
} catch (UnsupportedMessageException e) {
|
||||||
if (actionRes instanceof DataflowError dataflowError) {
|
if (actionRes instanceof DataflowError dataflowError) {
|
||||||
var txt = Text.create("Result of assert action is a dataflow error: " + dataflowError);
|
var txt = Text.create("Result of assert action is a dataflow error: " + dataflowError);
|
||||||
throw new PanicException(
|
throw new PanicException(builtins.error().makeAssertionError(txt), this);
|
||||||
builtins.error().makeAssertionError(txt), this);
|
|
||||||
} else {
|
} else {
|
||||||
var typeError =
|
var typeError =
|
||||||
builtins
|
builtins
|
||||||
|
@ -15,7 +15,9 @@ public abstract class GCNode extends Node {
|
|||||||
|
|
||||||
public abstract Object execute();
|
public abstract Object execute();
|
||||||
|
|
||||||
/** @return A new GCNode. */
|
/**
|
||||||
|
* @return A new GCNode.
|
||||||
|
*/
|
||||||
public static GCNode build() {
|
public static GCNode build() {
|
||||||
return GCNodeGen.create();
|
return GCNodeGen.create();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import org.enso.interpreter.runtime.state.State;
|
|||||||
type = "Runtime",
|
type = "Runtime",
|
||||||
name = "no_inline_with_arg",
|
name = "no_inline_with_arg",
|
||||||
description =
|
description =
|
||||||
"Runs its first argument applied to the second argument without the possibility of the call or its argument getting inlined.",
|
"Runs its first argument applied to the second argument without the possibility of the call"
|
||||||
|
+ " or its argument getting inlined.",
|
||||||
autoRegister = false)
|
autoRegister = false)
|
||||||
public class NoInlineWithArgNode extends Node {
|
public class NoInlineWithArgNode extends Node {
|
||||||
private @Child InvokeCallableNode invokeCallableNode;
|
private @Child InvokeCallableNode invokeCallableNode;
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
package org.enso.interpreter.node.expression.builtin.text.util;
|
package org.enso.interpreter.node.expression.builtin.text.util;
|
||||||
|
|
||||||
import org.enso.interpreter.node.expression.builtin.meta.TypeOfNode;
|
|
||||||
import org.enso.interpreter.runtime.EnsoContext;
|
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.dsl.NeverDefault;
|
import com.oracle.truffle.api.dsl.NeverDefault;
|
||||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
|
import org.enso.interpreter.node.expression.builtin.meta.TypeOfNode;
|
||||||
|
import org.enso.interpreter.runtime.EnsoContext;
|
||||||
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
|
|
||||||
public final class TypeToDisplayTextNode extends Node {
|
public final class TypeToDisplayTextNode extends Node {
|
||||||
@Child
|
@Child private TypeOfNode typeOfNode;
|
||||||
private TypeOfNode typeOfNode;
|
|
||||||
|
|
||||||
private TypeToDisplayTextNode(TypeOfNode typeOfNode) {
|
private TypeToDisplayTextNode(TypeOfNode typeOfNode) {
|
||||||
this.typeOfNode = typeOfNode;
|
this.typeOfNode = typeOfNode;
|
||||||
|
@ -114,7 +114,8 @@ public abstract class EvalNode extends BaseNode {
|
|||||||
@Cached("toJavaStringNode.execute(expression)") String expressionStr,
|
@Cached("toJavaStringNode.execute(expression)") String expressionStr,
|
||||||
@Cached("callerInfo") CallerInfo cachedCallerInfo,
|
@Cached("callerInfo") CallerInfo cachedCallerInfo,
|
||||||
@Cached(
|
@Cached(
|
||||||
"parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(), expressionStr)")
|
"parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(),"
|
||||||
|
+ " expressionStr)")
|
||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Shared("thunkExecutorNode") @Cached("build()") ThunkExecutorNode thunkExecutorNode) {
|
@Shared("thunkExecutorNode") @Cached("build()") ThunkExecutorNode thunkExecutorNode) {
|
||||||
Function thunk = Function.thunk(cachedCallTarget, callerInfo.getFrame());
|
Function thunk = Function.thunk(cachedCallTarget, callerInfo.getFrame());
|
||||||
|
@ -4,7 +4,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import org.enso.compiler.core.IR;
|
|
||||||
import org.enso.compiler.core.ir.Expression;
|
import org.enso.compiler.core.ir.Expression;
|
||||||
import org.enso.compiler.core.ir.Literal;
|
import org.enso.compiler.core.ir.Literal;
|
||||||
import org.enso.interpreter.node.ExpressionNode;
|
import org.enso.interpreter.node.ExpressionNode;
|
||||||
@ -13,7 +12,8 @@ import org.enso.interpreter.runtime.tag.Patchable;
|
|||||||
|
|
||||||
/** Generic literal node. */
|
/** Generic literal node. */
|
||||||
@NodeInfo(shortName = "Literal", description = "Constant literal expression")
|
@NodeInfo(shortName = "Literal", description = "Constant literal expression")
|
||||||
final class PatchableLiteralNode extends ExpressionNode implements Patchable, Predicate<Expression> {
|
final class PatchableLiteralNode extends ExpressionNode
|
||||||
|
implements Patchable, Predicate<Expression> {
|
||||||
private final LiteralNode node;
|
private final LiteralNode node;
|
||||||
private Object value;
|
private Object value;
|
||||||
|
|
||||||
@ -72,5 +72,4 @@ final class PatchableLiteralNode extends ExpressionNode implements Patchable, Pr
|
|||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,5 @@
|
|||||||
package org.enso.interpreter.runtime;
|
package org.enso.interpreter.runtime;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.enso.compiler.Compiler;
|
|
||||||
import org.enso.compiler.PackageRepository;
|
|
||||||
import org.enso.compiler.PackageRepositoryUtils;
|
|
||||||
import org.enso.compiler.data.CompilerConfig;
|
|
||||||
import org.enso.distribution.DistributionManager;
|
|
||||||
import org.enso.distribution.locking.LockManager;
|
|
||||||
import org.enso.editions.LibraryName;
|
|
||||||
import org.enso.interpreter.EnsoLanguage;
|
|
||||||
import org.enso.interpreter.OptionsHelper;
|
|
||||||
import org.enso.interpreter.instrument.NotificationHandler;
|
|
||||||
import org.enso.interpreter.runtime.builtin.Builtins;
|
|
||||||
import org.enso.interpreter.runtime.data.Type;
|
|
||||||
import org.enso.interpreter.runtime.scope.TopLevelScope;
|
|
||||||
import org.enso.interpreter.runtime.state.ExecutionEnvironment;
|
|
||||||
import org.enso.interpreter.runtime.state.State;
|
|
||||||
import org.enso.interpreter.runtime.util.TruffleFileSystem;
|
|
||||||
import org.enso.librarymanager.ProjectLoadingFailure;
|
|
||||||
import org.enso.librarymanager.resolved.LibraryRoot;
|
|
||||||
import org.enso.pkg.Package;
|
|
||||||
import org.enso.pkg.PackageManager;
|
|
||||||
import org.enso.pkg.QualifiedName;
|
|
||||||
import org.enso.polyglot.LanguageInfo;
|
|
||||||
import org.enso.polyglot.RuntimeOptions;
|
|
||||||
import org.enso.polyglot.debugger.IdExecutionService;
|
|
||||||
import org.graalvm.options.OptionKey;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.Assumption;
|
import com.oracle.truffle.api.Assumption;
|
||||||
import com.oracle.truffle.api.CallTarget;
|
import com.oracle.truffle.api.CallTarget;
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
@ -63,38 +19,74 @@ import com.oracle.truffle.api.io.TruffleProcessBuilder;
|
|||||||
import com.oracle.truffle.api.nodes.Node;
|
import com.oracle.truffle.api.nodes.Node;
|
||||||
import com.oracle.truffle.api.object.Shape;
|
import com.oracle.truffle.api.object.Shape;
|
||||||
import com.oracle.truffle.api.source.Source;
|
import com.oracle.truffle.api.source.Source;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.enso.compiler.Compiler;
|
||||||
|
import org.enso.compiler.PackageRepository;
|
||||||
|
import org.enso.compiler.PackageRepositoryUtils;
|
||||||
|
import org.enso.compiler.data.CompilerConfig;
|
||||||
|
import org.enso.distribution.DistributionManager;
|
||||||
|
import org.enso.distribution.locking.LockManager;
|
||||||
|
import org.enso.editions.LibraryName;
|
||||||
|
import org.enso.interpreter.EnsoLanguage;
|
||||||
|
import org.enso.interpreter.OptionsHelper;
|
||||||
|
import org.enso.interpreter.instrument.NotificationHandler;
|
||||||
|
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||||
|
import org.enso.interpreter.runtime.data.Type;
|
||||||
import org.enso.interpreter.runtime.data.text.Text;
|
import org.enso.interpreter.runtime.data.text.Text;
|
||||||
import org.enso.interpreter.runtime.error.PanicException;
|
import org.enso.interpreter.runtime.error.PanicException;
|
||||||
|
import org.enso.interpreter.runtime.scope.TopLevelScope;
|
||||||
|
import org.enso.interpreter.runtime.state.ExecutionEnvironment;
|
||||||
|
import org.enso.interpreter.runtime.state.State;
|
||||||
|
import org.enso.interpreter.runtime.util.TruffleFileSystem;
|
||||||
|
import org.enso.librarymanager.ProjectLoadingFailure;
|
||||||
|
import org.enso.librarymanager.resolved.LibraryRoot;
|
||||||
|
import org.enso.pkg.Package;
|
||||||
|
import org.enso.pkg.PackageManager;
|
||||||
|
import org.enso.pkg.QualifiedName;
|
||||||
|
import org.enso.polyglot.LanguageInfo;
|
||||||
|
import org.enso.polyglot.RuntimeOptions;
|
||||||
|
import org.enso.polyglot.debugger.IdExecutionService;
|
||||||
|
import org.graalvm.options.OptionKey;
|
||||||
import scala.jdk.javaapi.OptionConverters;
|
import scala.jdk.javaapi.OptionConverters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The language context is the internal state of the language that is associated
|
* The language context is the internal state of the language that is associated with each thread in
|
||||||
* with each thread in a running Enso program.
|
* a running Enso program.
|
||||||
*/
|
*/
|
||||||
public final class EnsoContext {
|
public final class EnsoContext {
|
||||||
|
|
||||||
private static final TruffleLanguage.ContextReference<EnsoContext> REFERENCE
|
private static final TruffleLanguage.ContextReference<EnsoContext> REFERENCE =
|
||||||
= TruffleLanguage.ContextReference.create(EnsoLanguage.class);
|
TruffleLanguage.ContextReference.create(EnsoLanguage.class);
|
||||||
|
|
||||||
private final EnsoLanguage language;
|
private final EnsoLanguage language;
|
||||||
private final Env environment;
|
private final Env environment;
|
||||||
private final HostClassLoader hostClassLoader = new HostClassLoader();
|
private final HostClassLoader hostClassLoader = new HostClassLoader();
|
||||||
private final boolean assertionsEnabled;
|
private final boolean assertionsEnabled;
|
||||||
private final boolean isPrivateCheckDisabled;
|
private final boolean isPrivateCheckDisabled;
|
||||||
private @CompilationFinal
|
private @CompilationFinal Compiler compiler;
|
||||||
Compiler compiler;
|
|
||||||
private final PrintStream out;
|
private final PrintStream out;
|
||||||
private final PrintStream err;
|
private final PrintStream err;
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final BufferedReader inReader;
|
private final BufferedReader inReader;
|
||||||
private @CompilationFinal
|
private @CompilationFinal PackageRepository packageRepository;
|
||||||
PackageRepository packageRepository;
|
private @CompilationFinal TopLevelScope topScope;
|
||||||
private @CompilationFinal
|
|
||||||
TopLevelScope topScope;
|
|
||||||
private final ThreadManager threadManager;
|
private final ThreadManager threadManager;
|
||||||
private final ThreadExecutors threadExecutors;
|
private final ThreadExecutors threadExecutors;
|
||||||
private final ResourceManager resourceManager;
|
private final ResourceManager resourceManager;
|
||||||
@ -126,12 +118,12 @@ public final class EnsoContext {
|
|||||||
* @param distributionManager a distribution manager
|
* @param distributionManager a distribution manager
|
||||||
*/
|
*/
|
||||||
public EnsoContext(
|
public EnsoContext(
|
||||||
EnsoLanguage language,
|
EnsoLanguage language,
|
||||||
String home,
|
String home,
|
||||||
Env environment,
|
Env environment,
|
||||||
NotificationHandler notificationHandler,
|
NotificationHandler notificationHandler,
|
||||||
LockManager lockManager,
|
LockManager lockManager,
|
||||||
DistributionManager distributionManager) {
|
DistributionManager distributionManager) {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.out = new PrintStream(environment.out());
|
this.out = new PrintStream(environment.out());
|
||||||
@ -143,20 +135,20 @@ public final class EnsoContext {
|
|||||||
this.resourceManager = new ResourceManager(this);
|
this.resourceManager = new ResourceManager(this);
|
||||||
this.isInlineCachingDisabled = getOption(RuntimeOptions.DISABLE_INLINE_CACHES_KEY);
|
this.isInlineCachingDisabled = getOption(RuntimeOptions.DISABLE_INLINE_CACHES_KEY);
|
||||||
var isParallelismEnabled = getOption(RuntimeOptions.ENABLE_AUTO_PARALLELISM_KEY);
|
var isParallelismEnabled = getOption(RuntimeOptions.ENABLE_AUTO_PARALLELISM_KEY);
|
||||||
this.isIrCachingDisabled
|
this.isIrCachingDisabled =
|
||||||
= getOption(RuntimeOptions.DISABLE_IR_CACHES_KEY) || isParallelismEnabled;
|
getOption(RuntimeOptions.DISABLE_IR_CACHES_KEY) || isParallelismEnabled;
|
||||||
this.isPrivateCheckDisabled = getOption(RuntimeOptions.DISABLE_PRIVATE_CHECK_KEY);
|
this.isPrivateCheckDisabled = getOption(RuntimeOptions.DISABLE_PRIVATE_CHECK_KEY);
|
||||||
this.executionEnvironment = getOption(EnsoLanguage.EXECUTION_ENVIRONMENT);
|
this.executionEnvironment = getOption(EnsoLanguage.EXECUTION_ENVIRONMENT);
|
||||||
this.assertionsEnabled = shouldAssertionsBeEnabled();
|
this.assertionsEnabled = shouldAssertionsBeEnabled();
|
||||||
this.shouldWaitForPendingSerializationJobs
|
this.shouldWaitForPendingSerializationJobs =
|
||||||
= getOption(RuntimeOptions.WAIT_FOR_PENDING_SERIALIZATION_JOBS_KEY);
|
getOption(RuntimeOptions.WAIT_FOR_PENDING_SERIALIZATION_JOBS_KEY);
|
||||||
this.compilerConfig
|
this.compilerConfig =
|
||||||
= new CompilerConfig(
|
new CompilerConfig(
|
||||||
isParallelismEnabled,
|
isParallelismEnabled,
|
||||||
true,
|
true,
|
||||||
!isPrivateCheckDisabled,
|
!isPrivateCheckDisabled,
|
||||||
getOption(RuntimeOptions.STRICT_ERRORS_KEY),
|
getOption(RuntimeOptions.STRICT_ERRORS_KEY),
|
||||||
scala.Option.empty());
|
scala.Option.empty());
|
||||||
this.home = home;
|
this.home = home;
|
||||||
this.builtins = new Builtins(this);
|
this.builtins = new Builtins(this);
|
||||||
this.notificationHandler = notificationHandler;
|
this.notificationHandler = notificationHandler;
|
||||||
@ -165,46 +157,44 @@ public final class EnsoContext {
|
|||||||
this.warningsLimit = getOption(RuntimeOptions.WARNINGS_LIMIT_KEY);
|
this.warningsLimit = getOption(RuntimeOptions.WARNINGS_LIMIT_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Perform expensive initialization logic for the context. */
|
||||||
* Perform expensive initialization logic for the context.
|
|
||||||
*/
|
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
TruffleFileSystem fs = new TruffleFileSystem();
|
TruffleFileSystem fs = new TruffleFileSystem();
|
||||||
PackageManager<TruffleFile> packageManager = new PackageManager<>(fs);
|
PackageManager<TruffleFile> packageManager = new PackageManager<>(fs);
|
||||||
|
|
||||||
Optional<TruffleFile> projectRoot = OptionsHelper.getProjectRoot(environment);
|
Optional<TruffleFile> projectRoot = OptionsHelper.getProjectRoot(environment);
|
||||||
Optional<Package<TruffleFile>> projectPackage
|
Optional<Package<TruffleFile>> projectPackage =
|
||||||
= projectRoot.map(
|
projectRoot.map(
|
||||||
file
|
file ->
|
||||||
-> packageManager
|
packageManager
|
||||||
.loadPackage(file)
|
.loadPackage(file)
|
||||||
.fold(
|
.fold(
|
||||||
err -> {
|
err -> {
|
||||||
throw new ProjectLoadingFailure(file.getName(), err);
|
throw new ProjectLoadingFailure(file.getName(), err);
|
||||||
},
|
},
|
||||||
res -> res));
|
res -> res));
|
||||||
|
|
||||||
Optional<String> languageHome
|
Optional<String> languageHome =
|
||||||
= OptionsHelper.getLanguageHomeOverride(environment).or(() -> Optional.ofNullable(home));
|
OptionsHelper.getLanguageHomeOverride(environment).or(() -> Optional.ofNullable(home));
|
||||||
var editionOverride = OptionsHelper.getEditionOverride(environment);
|
var editionOverride = OptionsHelper.getEditionOverride(environment);
|
||||||
var resourceManager = new org.enso.distribution.locking.ResourceManager(lockManager);
|
var resourceManager = new org.enso.distribution.locking.ResourceManager(lockManager);
|
||||||
|
|
||||||
packageRepository
|
packageRepository =
|
||||||
= DefaultPackageRepository.initializeRepository(
|
DefaultPackageRepository.initializeRepository(
|
||||||
OptionConverters.toScala(projectPackage),
|
OptionConverters.toScala(projectPackage),
|
||||||
OptionConverters.toScala(languageHome),
|
OptionConverters.toScala(languageHome),
|
||||||
OptionConverters.toScala(editionOverride),
|
OptionConverters.toScala(editionOverride),
|
||||||
distributionManager,
|
distributionManager,
|
||||||
resourceManager,
|
resourceManager,
|
||||||
this,
|
this,
|
||||||
builtins,
|
builtins,
|
||||||
notificationHandler);
|
notificationHandler);
|
||||||
topScope = new TopLevelScope(builtins, packageRepository);
|
topScope = new TopLevelScope(builtins, packageRepository);
|
||||||
this.compiler
|
this.compiler =
|
||||||
= new Compiler(new TruffleCompilerContext(this), packageRepository, compilerConfig);
|
new Compiler(new TruffleCompilerContext(this), packageRepository, compilerConfig);
|
||||||
|
|
||||||
projectPackage.ifPresent(
|
projectPackage.ifPresent(
|
||||||
pkg -> packageRepository.registerMainProjectPackage(pkg.libraryName(), pkg));
|
pkg -> packageRepository.registerMainProjectPackage(pkg.libraryName(), pkg));
|
||||||
|
|
||||||
var preinit = environment.getOptions().get(RuntimeOptions.PREINITIALIZE_KEY);
|
var preinit = environment.getOptions().get(RuntimeOptions.PREINITIALIZE_KEY);
|
||||||
if (preinit != null && preinit.length() > 0) {
|
if (preinit != null && preinit.length() > 0) {
|
||||||
@ -218,8 +208,7 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node the location of context access. Pass {@code null} if not in a
|
* @param node the location of context access. Pass {@code null} if not in a node.
|
||||||
* node.
|
|
||||||
* @return the proper context instance for the current {@link
|
* @return the proper context instance for the current {@link
|
||||||
* com.oracle.truffle.api.TruffleContext}.
|
* com.oracle.truffle.api.TruffleContext}.
|
||||||
*/
|
*/
|
||||||
@ -231,7 +220,8 @@ public final class EnsoContext {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Assumption checkNodes = Truffle.getRuntime().createAssumption("context check");
|
private static final Assumption checkNodes =
|
||||||
|
Truffle.getRuntime().createAssumption("context check");
|
||||||
private static final Set<Node> reportedNulllRootNodes = new HashSet<>();
|
private static final Set<Node> reportedNulllRootNodes = new HashSet<>();
|
||||||
private static long checkUntil = Long.MAX_VALUE;
|
private static long checkUntil = Long.MAX_VALUE;
|
||||||
|
|
||||||
@ -241,15 +231,16 @@ public final class EnsoContext {
|
|||||||
checkNodes.invalidate();
|
checkNodes.invalidate();
|
||||||
}
|
}
|
||||||
if (reportedNulllRootNodes.add(n)) {
|
if (reportedNulllRootNodes.add(n)) {
|
||||||
var ex = new Exception("""
|
var ex =
|
||||||
|
new Exception(
|
||||||
|
"""
|
||||||
no root node for {n}
|
no root node for {n}
|
||||||
with section: {s}
|
with section: {s}
|
||||||
with root nodes: {r}
|
with root nodes: {r}
|
||||||
"""
|
"""
|
||||||
.replace("{n}", "" + n)
|
.replace("{n}", "" + n)
|
||||||
.replace("{s}", "" + n.getEncapsulatingSourceSection())
|
.replace("{s}", "" + n.getEncapsulatingSourceSection())
|
||||||
.replace("{r}", "" + n.getRootNode())
|
.replace("{r}", "" + n.getRootNode()));
|
||||||
);
|
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
checkUntil = System.currentTimeMillis() + 10000;
|
checkUntil = System.currentTimeMillis() + 10000;
|
||||||
}
|
}
|
||||||
@ -259,9 +250,7 @@ public final class EnsoContext {
|
|||||||
return REFERENCE;
|
return REFERENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Performs eventual cleanup before the context is disposed of. */
|
||||||
* Performs eventual cleanup before the context is disposed of.
|
|
||||||
*/
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
threadExecutors.shutdown();
|
threadExecutors.shutdown();
|
||||||
threadManager.shutdown();
|
threadManager.shutdown();
|
||||||
@ -296,15 +285,11 @@ public final class EnsoContext {
|
|||||||
/**
|
/**
|
||||||
* Gets the compiler instance.
|
* Gets the compiler instance.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>The compiler is the portion of the interpreter that performs static analysis and
|
||||||
* The compiler is the portion of the interpreter that performs static
|
* transformation passes on the input program. A handle to the compiler lets you execute various
|
||||||
* analysis and transformation passes on the input program. A handle to the
|
* portions of the compilation pipeline, including parsing, analysis, and final code generation.
|
||||||
* compiler lets you execute various portions of the compilation pipeline,
|
|
||||||
* including parsing, analysis, and final code generation.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>Having this access available means that Enso programs can metaprogram Enso itself.
|
||||||
* Having this access available means that Enso programs can metaprogram Enso
|
|
||||||
* itself.
|
|
||||||
*
|
*
|
||||||
* @return a handle to the compiler
|
* @return a handle to the compiler
|
||||||
*/
|
*/
|
||||||
@ -356,12 +341,11 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the module name associated with a given file, using the environment
|
* Fetches the module name associated with a given file, using the environment packages
|
||||||
* packages information.
|
* information.
|
||||||
*
|
*
|
||||||
* @param path the path to decode.
|
* @param path the path to decode.
|
||||||
* @return a qualified name of the module corresponding to the file, if
|
* @return a qualified name of the module corresponding to the file, if exists.
|
||||||
* exists.
|
|
||||||
*/
|
*/
|
||||||
public Optional<QualifiedName> getModuleNameForFile(File path) {
|
public Optional<QualifiedName> getModuleNameForFile(File path) {
|
||||||
TruffleFile p = getTruffleFile(path);
|
TruffleFile p = getTruffleFile(path);
|
||||||
@ -369,12 +353,11 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the module name associated with a given file, using the environment
|
* Fetches the module name associated with a given file, using the environment packages
|
||||||
* packages information.
|
* information.
|
||||||
*
|
*
|
||||||
* @param file the path to decode.
|
* @param file the path to decode.
|
||||||
* @return a qualified name of the module corresponding to the file, if
|
* @return a qualified name of the module corresponding to the file, if exists.
|
||||||
* exists.
|
|
||||||
*/
|
*/
|
||||||
public Optional<QualifiedName> getModuleNameForFile(TruffleFile file) {
|
public Optional<QualifiedName> getModuleNameForFile(TruffleFile file) {
|
||||||
return PackageRepositoryUtils.getModuleNameForFile(packageRepository, file);
|
return PackageRepositoryUtils.getModuleNameForFile(packageRepository, file);
|
||||||
@ -428,8 +411,8 @@ public final class EnsoContext {
|
|||||||
*/
|
*/
|
||||||
public Optional<Module> findModuleByExpressionId(UUID expressionId) {
|
public Optional<Module> findModuleByExpressionId(UUID expressionId) {
|
||||||
return getTopScope().getModules().stream()
|
return getTopScope().getModules().stream()
|
||||||
.filter(m -> m.containsUUID(expressionId))
|
.filter(m -> m.containsUUID(expressionId))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -440,12 +423,12 @@ public final class EnsoContext {
|
|||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public void addToClassPath(TruffleFile file) {
|
public void addToClassPath(TruffleFile file) {
|
||||||
if (findGuestJava() == null) {
|
if (findGuestJava() == null) {
|
||||||
try {
|
try {
|
||||||
var url = file.toUri().toURL();
|
var url = file.toUri().toURL();
|
||||||
hostClassLoader.add(url);
|
hostClassLoader.add(url);
|
||||||
} catch (MalformedURLException ex) {
|
} catch (MalformedURLException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
var path = new File(file.toUri()).getAbsoluteFile();
|
var path = new File(file.toUri()).getAbsoluteFile();
|
||||||
@ -460,8 +443,8 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether provided object comes from Java. Either Java system
|
* Checks whether provided object comes from Java. Either Java system libraries or libraries added
|
||||||
* libraries or libraries added by {@link #addToClassPath(TruffleFile)}.
|
* by {@link #addToClassPath(TruffleFile)}.
|
||||||
*
|
*
|
||||||
* @param obj the object to check
|
* @param obj the object to check
|
||||||
* @return {@code true} or {@code false}
|
* @return {@code true} or {@code false}
|
||||||
@ -496,20 +479,18 @@ public final class EnsoContext {
|
|||||||
* @param obj java object
|
* @param obj java object
|
||||||
* @return wrapper object
|
* @return wrapper object
|
||||||
*/
|
*/
|
||||||
// @Deprecated(forRemoval=true)
|
// @Deprecated(forRemoval=true)
|
||||||
public Object asGuestValue(Object obj) {
|
public Object asGuestValue(Object obj) {
|
||||||
return environment.asGuestValue(obj);
|
return environment.asGuestValue(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to lookup a Java class (host symbol in Truffle terminology) by its
|
* Tries to lookup a Java class (host symbol in Truffle terminology) by its fully qualified name.
|
||||||
* fully qualified name. This method also tries to lookup inner classes. More
|
* This method also tries to lookup inner classes. More specifically, if the provided name
|
||||||
* specifically, if the provided name resolves to an inner class, then the
|
* resolves to an inner class, then the import of the outer class is resolved, and the inner class
|
||||||
* import of the outer class is resolved, and the inner class is looked up by
|
* is looked up by iterating the members of the outer class via Truffle's interop protocol.
|
||||||
* iterating the members of the outer class via Truffle's interop protocol.
|
|
||||||
*
|
*
|
||||||
* @param className Fully qualified class name, can also be nested static
|
* @param className Fully qualified class name, can also be nested static inner class.
|
||||||
* inner class.
|
|
||||||
* @return If the java class is found, return it, otherwise return null.
|
* @return If the java class is found, return it, otherwise return null.
|
||||||
*/
|
*/
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
@ -519,8 +500,8 @@ public final class EnsoContext {
|
|||||||
for (int i = items.size() - 1; i >= 0; i--) {
|
for (int i = items.size() - 1; i >= 0; i--) {
|
||||||
String pkgName = String.join(".", items.subList(0, i));
|
String pkgName = String.join(".", items.subList(0, i));
|
||||||
String curClassName = items.get(i);
|
String curClassName = items.get(i);
|
||||||
List<String> nestedClassPart
|
List<String> nestedClassPart =
|
||||||
= i < items.size() - 1 ? items.subList(i + 1, items.size()) : List.of();
|
i < items.size() - 1 ? items.subList(i + 1, items.size()) : List.of();
|
||||||
try {
|
try {
|
||||||
var hostSymbol = lookupHostSymbol(pkgName, curClassName);
|
var hostSymbol = lookupHostSymbol(pkgName, curClassName);
|
||||||
if (nestedClassPart.isEmpty()) {
|
if (nestedClassPart.isEmpty()) {
|
||||||
@ -540,11 +521,9 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Object lookupHostSymbol(String pkgName, String curClassName)
|
private Object lookupHostSymbol(String pkgName, String curClassName)
|
||||||
throws ClassNotFoundException, UnknownIdentifierException, UnsupportedMessageException {
|
throws ClassNotFoundException, UnknownIdentifierException, UnsupportedMessageException {
|
||||||
if (findGuestJava() == null) {
|
if (findGuestJava() == null) {
|
||||||
return environment.asHostSymbol(
|
return environment.asHostSymbol(hostClassLoader.loadClass(pkgName + "." + curClassName));
|
||||||
hostClassLoader.loadClass(pkgName + "." + curClassName)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return InteropLibrary.getUncached().readMember(findGuestJava(), pkgName + "." + curClassName);
|
return InteropLibrary.getUncached().readMember(findGuestJava(), pkgName + "." + curClassName);
|
||||||
}
|
}
|
||||||
@ -569,8 +548,11 @@ public final class EnsoContext {
|
|||||||
logger.log(Level.SEVERE, "Using experimental Espresso support!");
|
logger.log(Level.SEVERE, "Using experimental Espresso support!");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
if (ex.getMessage().contains("No language for id java found.")) {
|
if (ex.getMessage().contains("No language for id java found.")) {
|
||||||
logger.log(Level.SEVERE, "Environment variable ENSO_JAVA=" + envJava + ", but " + ex.getMessage());
|
logger.log(
|
||||||
logger.log(Level.SEVERE, "Use " + System.getProperty("java.home") + "/bin/gu install espresso");
|
Level.SEVERE,
|
||||||
|
"Environment variable ENSO_JAVA=" + envJava + ", but " + ex.getMessage());
|
||||||
|
logger.log(
|
||||||
|
Level.SEVERE, "Use " + System.getProperty("java.home") + "/bin/gu install espresso");
|
||||||
logger.log(Level.SEVERE, "Continuing in regular Java mode");
|
logger.log(Level.SEVERE, "Continuing in regular Java mode");
|
||||||
} else {
|
} else {
|
||||||
var ise = new IllegalStateException(ex.getMessage());
|
var ise = new IllegalStateException(ex.getMessage());
|
||||||
@ -579,7 +561,8 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Specify ENSO_JAVA=espresso to use Espresso. Was: " + envJava);
|
throw new IllegalStateException(
|
||||||
|
"Specify ENSO_JAVA=espresso to use Espresso. Was: " + envJava);
|
||||||
}
|
}
|
||||||
return guestJava;
|
return guestJava;
|
||||||
}
|
}
|
||||||
@ -603,7 +586,7 @@ public final class EnsoContext {
|
|||||||
public Optional<Module> createModuleForFile(File path) {
|
public Optional<Module> createModuleForFile(File path) {
|
||||||
TruffleFile f = getTruffleFile(path);
|
TruffleFile f = getTruffleFile(path);
|
||||||
return getModuleNameForFile(path)
|
return getModuleNameForFile(path)
|
||||||
.map(name -> getTopScope().createModule(name, getPackageOf(f).orElse(null), f));
|
.map(name -> getTopScope().createModule(name, getPackageOf(f).orElse(null), f));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -625,8 +608,8 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the atom constructor corresponding to the {@code Nothing} type, for
|
* Returns the atom constructor corresponding to the {@code Nothing} type, for builtin constructs
|
||||||
* builtin constructs that need to return an atom of this type.
|
* that need to return an atom of this type.
|
||||||
*
|
*
|
||||||
* @return the builtin {@code Nothing} atom constructor
|
* @return the builtin {@code Nothing} atom constructor
|
||||||
*/
|
*/
|
||||||
@ -675,8 +658,7 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks value of
|
* Checks value of {@link RuntimeOptions#INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_KEY}.
|
||||||
* {@link RuntimeOptions#INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_KEY}.
|
|
||||||
*
|
*
|
||||||
* @return the value of the option
|
* @return the value of the option
|
||||||
*/
|
*/
|
||||||
@ -693,9 +675,7 @@ public final class EnsoContext {
|
|||||||
return getOption(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS_KEY);
|
return getOption(RuntimeOptions.ENABLE_GLOBAL_SUGGESTIONS_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** The job parallelism or 1 */
|
||||||
* The job parallelism or 1
|
|
||||||
*/
|
|
||||||
public int getJobParallelism() {
|
public int getJobParallelism() {
|
||||||
var n = getOption(RuntimeOptions.JOB_PARALLELISM_KEY);
|
var n = getOption(RuntimeOptions.JOB_PARALLELISM_KEY);
|
||||||
var base = n == null ? 1 : n.intValue();
|
var base = n == null ? 1 : n.intValue();
|
||||||
@ -786,8 +766,8 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a logger for the specified class that is bound to this engine.
|
* Gets a logger for the specified class that is bound to this engine. Such logger may then be
|
||||||
* Such logger may then be safely used in threads defined in a thread-pool.
|
* safely used in threads defined in a thread-pool.
|
||||||
*
|
*
|
||||||
* @param clazz the class to name log entries with
|
* @param clazz the class to name log entries with
|
||||||
* @return a new logger for the specified {@code path}
|
* @return a new logger for the specified {@code path}
|
||||||
@ -797,11 +777,9 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current clock value and atomically increments the counter by
|
* Returns the current clock value and atomically increments the counter by one.
|
||||||
* one.
|
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>The counter is used to track the creation time of warnings.
|
||||||
* The counter is used to track the creation time of warnings.
|
|
||||||
*/
|
*/
|
||||||
public long nextSequenceId() {
|
public long nextSequenceId() {
|
||||||
return clock.getAndIncrement();
|
return clock.getAndIncrement();
|
||||||
@ -811,16 +789,12 @@ public final class EnsoContext {
|
|||||||
return executionEnvironment;
|
return executionEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Set the runtime execution environment of this context. */
|
||||||
* Set the runtime execution environment of this context.
|
|
||||||
*/
|
|
||||||
public void setExecutionEnvironment(ExecutionEnvironment executionEnvironment) {
|
public void setExecutionEnvironment(ExecutionEnvironment executionEnvironment) {
|
||||||
this.executionEnvironment = executionEnvironment;
|
this.executionEnvironment = executionEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Returns a maximal number of warnings that can be attached to a value */
|
||||||
* Returns a maximal number of warnings that can be attached to a value
|
|
||||||
*/
|
|
||||||
public int getWarningsLimit() {
|
public int getWarningsLimit() {
|
||||||
return this.warningsLimit;
|
return this.warningsLimit;
|
||||||
}
|
}
|
||||||
@ -846,8 +820,7 @@ public final class EnsoContext {
|
|||||||
|
|
||||||
public TruffleFile findLibraryRootPath(LibraryRoot root) {
|
public TruffleFile findLibraryRootPath(LibraryRoot root) {
|
||||||
return environment.getInternalTruffleFile(
|
return environment.getInternalTruffleFile(
|
||||||
root.location().toAbsolutePath().normalize().toString()
|
root.location().toAbsolutePath().normalize().toString());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TruffleFile getPublicTruffleFile(String path) {
|
public TruffleFile getPublicTruffleFile(String path) {
|
||||||
@ -867,8 +840,9 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Thread createThread(boolean systemThread, Runnable run) {
|
public Thread createThread(boolean systemThread, Runnable run) {
|
||||||
return systemThread ? environment.createSystemThread(run)
|
return systemThread
|
||||||
: environment.newTruffleThreadBuilder(run).build();
|
? environment.createSystemThread(run)
|
||||||
|
: environment.newTruffleThreadBuilder(run).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<Void> submitThreadLocal(Thread[] threads, ThreadLocalAction action) {
|
public Future<Void> submitThreadLocal(Thread[] threads, ThreadLocalAction action) {
|
||||||
@ -892,22 +866,20 @@ public final class EnsoContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to use when an unexpected state happens that should raise a panic,
|
* Helper method to use when an unexpected state happens that should raise a panic, but not crash
|
||||||
* but not crash the interpreter. Creates a {@link PanicException} with
|
* the interpreter. Creates a {@link PanicException} with <em>assertion error</em> payload.
|
||||||
* <em>assertion error</em> payload.
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @param node where the problem happened (may be {@code null})
|
* @param node where the problem happened (may be {@code null})
|
||||||
* @param message {@code null} (then {@code e.getMessage()} is used) or a special
|
* @param message {@code null} (then {@code e.getMessage()} is used) or a special message to use
|
||||||
* message to use in the panic
|
* in the panic
|
||||||
* @param e external exception to extract message and stack from or {@code null}
|
* @param e external exception to extract message and stack from or {@code null}
|
||||||
* @return this method never returns it throws the {@link PanicException}
|
* @return this method never returns it throws the {@link PanicException}
|
||||||
* @throws PanicException with <em>assertion error</em> payload
|
* @throws PanicException with <em>assertion error</em> payload
|
||||||
*/
|
*/
|
||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public PanicException raiseAssertionPanic(Node node, String message, Throwable e) throws PanicException {
|
public PanicException raiseAssertionPanic(Node node, String message, Throwable e)
|
||||||
|
throws PanicException {
|
||||||
String msg;
|
String msg;
|
||||||
String sep;
|
String sep;
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
|
@ -63,6 +63,7 @@ public final class Module implements EnsoObject {
|
|||||||
private final ModuleCache cache;
|
private final ModuleCache cache;
|
||||||
private boolean wasLoadedFromCache;
|
private boolean wasLoadedFromCache;
|
||||||
private final boolean synthetic;
|
private final boolean synthetic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This list is filled in case there is a directory with the same name as this module. The
|
* This list is filled in case there is a directory with the same name as this module. The
|
||||||
* directory then contains submodules of this module that should be directly accessible from this
|
* directory then contains submodules of this module that should be directly accessible from this
|
||||||
@ -188,17 +189,23 @@ public final class Module implements EnsoObject {
|
|||||||
this.compilationStage = CompilationStage.INITIAL;
|
this.compilationStage = CompilationStage.INITIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the literal source of this module. */
|
/**
|
||||||
|
* @return the literal source of this module.
|
||||||
|
*/
|
||||||
public Rope getLiteralSource() {
|
public Rope getLiteralSource() {
|
||||||
return sources.rope();
|
return sources.rope();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true if this module represents a synthetic (compiler-generated) module */
|
/**
|
||||||
|
* @return true if this module represents a synthetic (compiler-generated) module
|
||||||
|
*/
|
||||||
public boolean isSynthetic() {
|
public boolean isSynthetic() {
|
||||||
return synthetic;
|
return synthetic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true iff this module is private (project-private). */
|
/**
|
||||||
|
* @return true iff this module is private (project-private).
|
||||||
|
*/
|
||||||
public boolean isPrivate() {
|
public boolean isPrivate() {
|
||||||
return ir.isPrivate();
|
return ir.isPrivate();
|
||||||
}
|
}
|
||||||
@ -291,7 +298,9 @@ public final class Module implements EnsoObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the location of this module. */
|
/**
|
||||||
|
* @return the location of this module.
|
||||||
|
*/
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
return sources.getPath();
|
return sources.getPath();
|
||||||
}
|
}
|
||||||
@ -382,7 +391,9 @@ public final class Module implements EnsoObject {
|
|||||||
context.getCompiler().run(asCompilerModule());
|
context.getCompiler().run(asCompilerModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return IR defined by this module. */
|
/**
|
||||||
|
* @return IR defined by this module.
|
||||||
|
*/
|
||||||
public org.enso.compiler.core.ir.Module getIr() {
|
public org.enso.compiler.core.ir.Module getIr() {
|
||||||
return ir;
|
return ir;
|
||||||
}
|
}
|
||||||
@ -409,7 +420,9 @@ public final class Module implements EnsoObject {
|
|||||||
return map.containsKey(id);
|
return map.containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the current compilation stage of this module. */
|
/**
|
||||||
|
* @return the current compilation stage of this module.
|
||||||
|
*/
|
||||||
public CompilationStage getCompilationStage() {
|
public CompilationStage getCompilationStage() {
|
||||||
return compilationStage;
|
return compilationStage;
|
||||||
}
|
}
|
||||||
@ -439,7 +452,9 @@ public final class Module implements EnsoObject {
|
|||||||
this.uuidsMap = null;
|
this.uuidsMap = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the runtime scope of this module. */
|
/**
|
||||||
|
* @return the runtime scope of this module.
|
||||||
|
*/
|
||||||
public ModuleScope getScope() {
|
public ModuleScope getScope() {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
@ -458,7 +473,9 @@ public final class Module implements EnsoObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the qualified name of this module. */
|
/**
|
||||||
|
* @return the qualified name of this module.
|
||||||
|
*/
|
||||||
public QualifiedName getName() {
|
public QualifiedName getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -476,7 +493,9 @@ public final class Module implements EnsoObject {
|
|||||||
this.name = name.renameProject(newName);
|
this.name = name.renameProject(newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the indexed flag. */
|
/**
|
||||||
|
* @return the indexed flag.
|
||||||
|
*/
|
||||||
public boolean isIndexed() {
|
public boolean isIndexed() {
|
||||||
return isIndexed;
|
return isIndexed;
|
||||||
}
|
}
|
||||||
@ -486,27 +505,37 @@ public final class Module implements EnsoObject {
|
|||||||
isIndexed = indexed;
|
isIndexed = indexed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the source file of this module. */
|
/**
|
||||||
|
* @return the source file of this module.
|
||||||
|
*/
|
||||||
public TruffleFile getSourceFile() {
|
public TruffleFile getSourceFile() {
|
||||||
return sources.file();
|
return sources.file();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {@code true} if the module is interactive, {@code false} otherwise */
|
/**
|
||||||
|
* @return {@code true} if the module is interactive, {@code false} otherwise
|
||||||
|
*/
|
||||||
public boolean isInteractive() {
|
public boolean isInteractive() {
|
||||||
return patchedValues != null;
|
return patchedValues != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the cache for this module */
|
/**
|
||||||
|
* @return the cache for this module
|
||||||
|
*/
|
||||||
public ModuleCache getCache() {
|
public ModuleCache getCache() {
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {@code true} if the module was loaded from the cache, {@code false} otherwise */
|
/**
|
||||||
|
* @return {@code true} if the module was loaded from the cache, {@code false} otherwise
|
||||||
|
*/
|
||||||
public boolean wasLoadedFromCache() {
|
public boolean wasLoadedFromCache() {
|
||||||
return wasLoadedFromCache;
|
return wasLoadedFromCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param wasLoadedFromCache whether or not the module was loaded from the cache */
|
/**
|
||||||
|
* @param wasLoadedFromCache whether or not the module was loaded from the cache
|
||||||
|
*/
|
||||||
void setLoadedFromCache(boolean wasLoadedFromCache) {
|
void setLoadedFromCache(boolean wasLoadedFromCache) {
|
||||||
this.wasLoadedFromCache = wasLoadedFromCache;
|
this.wasLoadedFromCache = wasLoadedFromCache;
|
||||||
}
|
}
|
||||||
@ -543,7 +572,8 @@ public final class Module implements EnsoObject {
|
|||||||
TruffleLogger logger = TruffleLogger.getLogger(LanguageInfo.ID, Module.class);
|
TruffleLogger logger = TruffleLogger.getLogger(LanguageInfo.ID, Module.class);
|
||||||
logger.log(
|
logger.log(
|
||||||
Level.SEVERE,
|
Level.SEVERE,
|
||||||
"Failed to get the requested method. Try clearing your IR caches or disabling caching.");
|
"Failed to get the requested method. Try clearing your IR caches or disabling"
|
||||||
|
+ " caching.");
|
||||||
throw npe;
|
throw npe;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,25 +7,20 @@ import org.enso.pkg.QualifiedName;
|
|||||||
import org.enso.polyglot.LanguageInfo;
|
import org.enso.polyglot.LanguageInfo;
|
||||||
import org.enso.text.buffer.Rope;
|
import org.enso.text.buffer.Rope;
|
||||||
|
|
||||||
|
/**
|
||||||
/** Keeps information about various kinds of sources associated with a {@link Module}.
|
* Keeps information about various kinds of sources associated with a {@link Module}. All the record
|
||||||
* All the record fields are immutable. They can only change by creating new instance
|
* fields are immutable. They can only change by creating new instance of the whole record - usually
|
||||||
* of the whole record - usually via methods {@link #newWith(org.enso.text.buffer.Rope)}
|
* via methods {@link #newWith(org.enso.text.buffer.Rope)} or {@link
|
||||||
* or {@link #newWith(com.oracle.truffle.api.TruffleFile)}. The creation of
|
* #newWith(com.oracle.truffle.api.TruffleFile)}. The creation of cached Truffle {@link Source} is
|
||||||
* cached Truffle {@link Source} is delayed and happens only
|
* delayed and happens only per {@link #ensureCachedSource(org.enso.pkg.QualifiedName) request}.
|
||||||
* per {@link #ensureCachedSource(org.enso.pkg.QualifiedName) request}.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
record ModuleSources(
|
record ModuleSources(TruffleFile file, Rope rope, Source source) {
|
||||||
TruffleFile file,
|
|
||||||
Rope rope,
|
|
||||||
Source source) {
|
|
||||||
|
|
||||||
/** Empty triple of sources. Continue with {@code newWith} methods.
|
/** Empty triple of sources. Continue with {@code newWith} methods. */
|
||||||
*/
|
|
||||||
static final ModuleSources NONE = new ModuleSources(null, null, null);
|
static final ModuleSources NONE = new ModuleSources(null, null, null);
|
||||||
|
|
||||||
/** Creates sources instances associated with provided Truffle file.
|
/**
|
||||||
|
* Creates sources instances associated with provided Truffle file.
|
||||||
*
|
*
|
||||||
* @param f the file to associate the sources with
|
* @param f the file to associate the sources with
|
||||||
* @return new sources triple
|
* @return new sources triple
|
||||||
@ -34,8 +29,9 @@ record ModuleSources(
|
|||||||
return new ModuleSources(f, null, null);
|
return new ModuleSources(f, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Associates current sources with modified text content. The {@code file}
|
/**
|
||||||
* is kept unchanged. The cached {@code source} is cleared.
|
* Associates current sources with modified text content. The {@code file} is kept unchanged. The
|
||||||
|
* cached {@code source} is cleared.
|
||||||
*
|
*
|
||||||
* @param r the new text content to assign to the sources
|
* @param r the new text content to assign to the sources
|
||||||
* @return new sources triple
|
* @return new sources triple
|
||||||
@ -44,8 +40,9 @@ record ModuleSources(
|
|||||||
return new ModuleSources(file(), r, null);
|
return new ModuleSources(file(), r, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resets the contents of sources but retains the reference to the
|
/**
|
||||||
* file. Continue with {@code newWith} methods.
|
* Resets the contents of sources but retains the reference to the file. Continue with {@code
|
||||||
|
* newWith} methods.
|
||||||
*
|
*
|
||||||
* @return new sources triple
|
* @return new sources triple
|
||||||
*/
|
*/
|
||||||
@ -53,10 +50,10 @@ record ModuleSources(
|
|||||||
return new ModuleSources(file(), null, null);
|
return new ModuleSources(file(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes sure Truffle {@code Source} object is ready for the sources. If
|
/**
|
||||||
* this triple already contains Truffle source, it just returns itself.
|
* Makes sure Truffle {@code Source} object is ready for the sources. If this triple already
|
||||||
* Otherwise, if the {@link #rope() content} is set, it is used as chars
|
* contains Truffle source, it just returns itself. Otherwise, if the {@link #rope() content} is
|
||||||
* for the Truffle source. If the file isn't in memory yet, it is read in
|
* set, it is used as chars for the Truffle source. If the file isn't in memory yet, it is read in
|
||||||
* and both {@link #source()} and {@link #rope()} are initialized.
|
* and both {@link #source()} and {@link #rope()} are initialized.
|
||||||
*
|
*
|
||||||
* @param name the name of the associated module
|
* @param name the name of the associated module
|
||||||
@ -78,7 +75,8 @@ record ModuleSources(
|
|||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Path of the associated {@link #file()}.
|
/**
|
||||||
|
* Path of the associated {@link #file()}.
|
||||||
*
|
*
|
||||||
* @return path or {@code null}
|
* @return path or {@code null}
|
||||||
*/
|
*/
|
||||||
|
@ -7,43 +7,39 @@ import java.io.IOException;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import org.enso.compiler.context.SimpleUpdate;
|
import org.enso.compiler.context.SimpleUpdate;
|
||||||
import org.enso.compiler.core.IR;
|
|
||||||
import org.enso.compiler.core.ir.Expression;
|
import org.enso.compiler.core.ir.Expression;
|
||||||
import org.enso.interpreter.runtime.callable.function.Function;
|
import org.enso.interpreter.runtime.callable.function.Function;
|
||||||
import org.enso.interpreter.runtime.tag.Patchable;
|
import org.enso.interpreter.runtime.tag.Patchable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps patched values for expression in module. Also keeps mapping of
|
* Keeps patched values for expression in module. Also keeps mapping of original source offset and
|
||||||
* original source offset and new {@link #findDelta(int, boolean) deltas}.
|
* new {@link #findDelta(int, boolean) deltas}.
|
||||||
*/
|
*/
|
||||||
final class PatchedModuleValues {
|
final class PatchedModuleValues {
|
||||||
private final Module module;
|
private final Module module;
|
||||||
private final TreeMap<Integer,int[]> deltas = new TreeMap<>();
|
private final TreeMap<Integer, int[]> deltas = new TreeMap<>();
|
||||||
private Map<Node, Predicate<Expression>> values;
|
private Map<Node, Predicate<Expression>> values;
|
||||||
|
|
||||||
PatchedModuleValues(Module module) {
|
PatchedModuleValues(Module module) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Disposes the binding. No-op currently.
|
/** Disposes the binding. No-op currently. */
|
||||||
*/
|
void dispose() {}
|
||||||
void dispose() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Keeps "deltas" for each {@code offset} where a modification happened.
|
/**
|
||||||
* Edits are always deleting few characters and inserting another few characters
|
* Keeps "deltas" for each {@code offset} where a modification happened. Edits are always deleting
|
||||||
* at a given location. The idea here is to use {@code SortedMap} to keep
|
* few characters and inserting another few characters at a given location. The idea here is to
|
||||||
* information about "deltas" at each offset of modification. Whenever new
|
* use {@code SortedMap} to keep information about "deltas" at each offset of modification.
|
||||||
* edit is made, the delta at its offset is recorded and all deltas after
|
* Whenever new edit is made, the delta at its offset is recorded and all deltas after the offset
|
||||||
* the offset adjusted as they shift too.
|
* adjusted as they shift too.
|
||||||
*
|
*
|
||||||
* @param collect {@link Node} to value map of the values to use
|
* @param collect {@link Node} to value map of the values to use
|
||||||
* @param offset location when a modification happened
|
* @param offset location when a modification happened
|
||||||
* @param delta positive or negative change at the offset location
|
* @param delta positive or negative change at the offset location
|
||||||
*/
|
*/
|
||||||
private synchronized void performUpdates(
|
private synchronized void performUpdates(
|
||||||
Map<Node, Predicate<Expression>> collect, int offset, int delta
|
Map<Node, Predicate<Expression>> collect, int offset, int delta) {
|
||||||
) {
|
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
var scope = module.getScope();
|
var scope = module.getScope();
|
||||||
values = new HashMap<>();
|
values = new HashMap<>();
|
||||||
@ -58,22 +54,23 @@ final class PatchedModuleValues {
|
|||||||
}
|
}
|
||||||
Map.Entry<Integer, int[]> previous = deltas.floorEntry(offset);
|
Map.Entry<Integer, int[]> previous = deltas.floorEntry(offset);
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
deltas.put(offset, new int[] { delta });
|
deltas.put(offset, new int[] {delta});
|
||||||
} else if (previous.getKey() == offset) {
|
} else if (previous.getKey() == offset) {
|
||||||
previous.getValue()[0] += delta;
|
previous.getValue()[0] += delta;
|
||||||
} else {
|
} else {
|
||||||
deltas.put(offset, new int[] { previous.getValue()[0] + delta });
|
deltas.put(offset, new int[] {previous.getValue()[0] + delta});
|
||||||
}
|
}
|
||||||
for (int[] after : deltas.tailMap(offset, false).values()) {
|
for (int[] after : deltas.tailMap(offset, false).values()) {
|
||||||
after[0] += delta;
|
after[0] += delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Checks whether a simple edit is applicable and performs it if so.
|
/**
|
||||||
|
* Checks whether a simple edit is applicable and performs it if so.
|
||||||
*
|
*
|
||||||
* @param update information about the edit to be done
|
* @param update information about the edit to be done
|
||||||
* @return {@code true} if the edit was applied, {@code false} to proceed with
|
* @return {@code true} if the edit was applied, {@code false} to proceed with full re-parse of
|
||||||
* full re-parse of the source
|
* the source
|
||||||
*/
|
*/
|
||||||
boolean simpleUpdate(SimpleUpdate update) {
|
boolean simpleUpdate(SimpleUpdate update) {
|
||||||
var scope = module.getScope();
|
var scope = module.getScope();
|
||||||
@ -110,13 +107,15 @@ final class PatchedModuleValues {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateFunctionsMap(SimpleUpdate edit, List<Function> values, Map<Node, Predicate<Expression>> nodeValues) {
|
private static void updateFunctionsMap(
|
||||||
|
SimpleUpdate edit, List<Function> values, Map<Node, Predicate<Expression>> nodeValues) {
|
||||||
for (Function f : values) {
|
for (Function f : values) {
|
||||||
updateNode(edit, f.getCallTarget().getRootNode(), nodeValues);
|
updateNode(edit, f.getCallTarget().getRootNode(), nodeValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateNode(SimpleUpdate update, Node root, Map<Node, Predicate<Expression>> nodeValues) {
|
private static void updateNode(
|
||||||
|
SimpleUpdate update, Node root, Map<Node, Predicate<Expression>> nodeValues) {
|
||||||
LinkedList<Node> queue = new LinkedList<>();
|
LinkedList<Node> queue = new LinkedList<>();
|
||||||
queue.add(root);
|
queue.add(root);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
@ -140,12 +139,10 @@ final class PatchedModuleValues {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (n instanceof Patchable node) {
|
if (n instanceof Patchable node) {
|
||||||
if (
|
if (at.getStartLine() - 1 == edit.range().start().line()
|
||||||
at.getStartLine() - 1 == edit.range().start().line() &&
|
&& at.getStartColumn() - 1 == edit.range().start().character()
|
||||||
at.getStartColumn() - 1 == edit.range().start().character() &&
|
&& at.getEndLine() - 1 == edit.range().end().line()
|
||||||
at.getEndLine() - 1 == edit.range().end().line() &&
|
&& at.getEndColumn() == edit.range().end().character()) {
|
||||||
at.getEndColumn() == edit.range().end().character()
|
|
||||||
) {
|
|
||||||
var patchableNode = node.asPatchableNode();
|
var patchableNode = node.asPatchableNode();
|
||||||
if (patchableNode.test(update.newIr())) {
|
if (patchableNode.test(update.newIr())) {
|
||||||
nodeValues.put(patchableNode, patchableNode);
|
nodeValues.put(patchableNode, patchableNode);
|
||||||
@ -164,12 +161,13 @@ final class PatchedModuleValues {
|
|||||||
* Finds difference against location in the original source code.
|
* Finds difference against location in the original source code.
|
||||||
*
|
*
|
||||||
* @param offset the original location
|
* @param offset the original location
|
||||||
* @param inclusive are modifications at the same location going to count or not
|
* @param inclusive are modifications at the same location going to count or not - they count for
|
||||||
* - they count for section ends, but do not count for section starts
|
* section ends, but do not count for section starts
|
||||||
* @return positive or negative delta to apply at given offset
|
* @return positive or negative delta to apply at given offset
|
||||||
*/
|
*/
|
||||||
int findDelta(int offset, boolean inclusive) {
|
int findDelta(int offset, boolean inclusive) {
|
||||||
Map.Entry<Integer, int[]> previous = inclusive ? deltas.floorEntry(offset) : deltas.lowerEntry(offset);
|
Map.Entry<Integer, int[]> previous =
|
||||||
|
inclusive ? deltas.floorEntry(offset) : deltas.lowerEntry(offset);
|
||||||
return previous == null ? 0 : previous.getValue()[0];
|
return previous == null ? 0 : previous.getValue()[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ public class ResourceManager {
|
|||||||
private volatile Thread workerThread;
|
private volatile Thread workerThread;
|
||||||
private final Runner worker = new Runner();
|
private final Runner worker = new Runner();
|
||||||
private final ReferenceQueue<ManagedResource> referenceQueue = new ReferenceQueue<>();
|
private final ReferenceQueue<ManagedResource> referenceQueue = new ReferenceQueue<>();
|
||||||
private final ConcurrentMap<PhantomReference<ManagedResource>, Item> items = new ConcurrentHashMap<>();
|
private final ConcurrentMap<PhantomReference<ManagedResource>, Item> items =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of Resource Manager.
|
* Creates a new instance of Resource Manager.
|
||||||
@ -128,8 +129,9 @@ public class ResourceManager {
|
|||||||
@CompilerDirectives.TruffleBoundary
|
@CompilerDirectives.TruffleBoundary
|
||||||
public ManagedResource register(Object object, Object function) {
|
public ManagedResource register(Object object, Object function) {
|
||||||
if (isClosed) {
|
if (isClosed) {
|
||||||
throw EnsoContext.get(null).raiseAssertionPanic(null,
|
throw EnsoContext.get(null)
|
||||||
"Can't register new resources after resource manager is closed.", null);
|
.raiseAssertionPanic(
|
||||||
|
null, "Can't register new resources after resource manager is closed.", null);
|
||||||
}
|
}
|
||||||
if (workerThread == null || !workerThread.isAlive()) {
|
if (workerThread == null || !workerThread.isAlive()) {
|
||||||
worker.setKilled(false);
|
worker.setKilled(false);
|
||||||
@ -227,7 +229,11 @@ public class ResourceManager {
|
|||||||
* @param reference a phantom reference used for tracking the reachability status of the
|
* @param reference a phantom reference used for tracking the reachability status of the
|
||||||
* resource.
|
* resource.
|
||||||
*/
|
*/
|
||||||
public Item(ManagedResource referent, Object underlying, Object finalizer, ReferenceQueue<ManagedResource> queue) {
|
public Item(
|
||||||
|
ManagedResource referent,
|
||||||
|
Object underlying,
|
||||||
|
Object finalizer,
|
||||||
|
ReferenceQueue<ManagedResource> queue) {
|
||||||
super(referent, queue);
|
super(referent, queue);
|
||||||
this.underlying = underlying;
|
this.underlying = underlying;
|
||||||
this.finalizer = finalizer;
|
this.finalizer = finalizer;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user