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:
Pavel Marek 2023-12-15 15:45:23 +01:00 committed by GitHub
parent 56cc9561b1
commit c1098865f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
297 changed files with 8839 additions and 6607 deletions

View File

@ -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:

View File

@ -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

View File

@ -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());

View File

@ -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);

View File

@ -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())

View File

@ -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. */

View File

@ -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()

View File

@ -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

View File

@ -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();
/** /**

View File

@ -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) {}
}

View File

@ -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
) {
}

View File

@ -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);

View File

@ -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

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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.

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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()) {

View File

@ -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()));
} }
} }

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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);
}; };
} }
} }

View File

@ -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 {

View File

@ -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() + "]";
} }
} }

View File

@ -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;

View File

@ -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;

View File

@ -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) {}
}
} }

View File

@ -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;
} }
} }

View File

@ -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) {}
} }

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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);
} }
} }

View File

@ -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");
} }
} }

View File

@ -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."));
} }
} }
} }

View File

@ -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());

View File

@ -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"));
} }
} }

View File

@ -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 =

View File

@ -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);
} }
} }

View File

@ -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 = \"""

View File

@ -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());
} }

View File

@ -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.

View File

@ -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();
} }

View File

@ -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;

View File

@ -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;
} }
} }
} }

View File

@ -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;
} }
} }

View File

@ -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 { }
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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));

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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();
} }

View File

@ -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();
} }

View File

@ -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();

View File

@ -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);
} }

View File

@ -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);

View File

@ -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 {

View File

@ -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;
} }
} }
} }

View File

@ -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);

View File

@ -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);
} }
} }

View File

@ -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();

View File

@ -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) {

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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.
* *

View File

@ -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

View File

@ -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);
} }

View File

@ -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;
} }
} }

View File

@ -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);

View File

@ -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());
} }

View File

@ -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));

View File

@ -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;
} }

View File

@ -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());
} }
} }
} }

View File

@ -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 {
} }
} }
} }

View File

@ -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());

View File

@ -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);
} }
} }

View File

@ -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();
} }
} }

View File

@ -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();
} }

View File

@ -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);
} }

View File

@ -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 =

View File

@ -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

View File

@ -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();
} }

View File

@ -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;

View File

@ -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;

View File

@ -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());

View File

@ -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;
}; };
} }
} }

View File

@ -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) {

View File

@ -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;
} }
} }

View File

@ -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}
*/ */

View File

@ -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];
} }
} }

View File

@ -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