diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java index 7442bde16576..551c3f8877d5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java @@ -25,10 +25,9 @@ static AddToClassPathNode build() { @CompilerDirectives.TruffleBoundary @Specialization Object doExecute(Object path, @Cached ExpectStringNode expectStringNode) { - EnsoContext context = EnsoContext.get(this); - context - .getEnvironment() - .addToHostClassPath(context.getTruffleFile(new File(expectStringNode.execute(path)))); - return context.getBuiltins().nothing(); + var ctx = EnsoContext.get(this); + var file = ctx.getTruffleFile(new File(expectStringNode.execute(path))); + ctx.addToHostClassPath(file); + return ctx.getBuiltins().nothing(); } } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java index 957c1ba7beb6..3c630f634de5 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java @@ -49,6 +49,7 @@ import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.TruffleLogger; +import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -383,6 +384,27 @@ public Optional findModuleByExpressionId(UUID expressionId) { .findFirst(); } + /** + * Modifies the classpath to use to lookup {@code polyglot java} imports. + * @param file the file to register + */ + @TruffleBoundary + public void addToHostClassPath(TruffleFile file) { + if (findGuestJava() == null) { + environment.addToHostClassPath(file); + } else { + try { + var path = new File(file.toUri()).getAbsoluteFile(); + if (!path.exists()) { + throw new IllegalStateException("File not found " + path); + } + InteropLibrary.getUncached().invokeMember(findGuestJava(), "addPath", path.getPath()); + } catch (InteropException ex) { + throw new IllegalStateException(ex); + } + } + } + /** * Tries to lookup a Java class (host symbol in Truffle terminology) by its fully qualified name. * This method also tries to lookup inner classes. More specifically, if the provided name @@ -401,24 +423,29 @@ public Object lookupJavaClass(String className) { List nestedClassPart = i < items.size() - 1 ? items.subList(i + 1, items.size()) : List.of(); try { - Object hostSymbol; - if (findGuestJava() == null) { - hostSymbol = environment.lookupHostSymbol(pkgName + "." + curClassName); - } else { - hostSymbol = InteropLibrary.getUncached().readMember(findGuestJava(), pkgName + "." + curClassName); - } + var hostSymbol = lookupHostSymbol(pkgName, curClassName); if (nestedClassPart.isEmpty()) { return hostSymbol; } else { - return getNestedClass(hostSymbol, nestedClassPart); + var fullInnerClassName = curClassName + "$" + String.join("$", nestedClassPart); + return lookupHostSymbol(pkgName, fullInnerClassName); } - } catch (RuntimeException | UnsupportedMessageException | UnknownIdentifierException ex) { + } catch (RuntimeException | InteropException ex) { logger.log(Level.WARNING, null, ex); } } return null; } + private Object lookupHostSymbol(String pkgName, String curClassName) + throws UnknownIdentifierException, UnsupportedMessageException { + if (findGuestJava() == null) { + return environment.lookupHostSymbol(pkgName + "." + curClassName); + } else { + return InteropLibrary.getUncached().readMember(findGuestJava(), pkgName + "." + curClassName); + } + } + private Object guestJava = this; @TruffleBoundary @@ -428,10 +455,14 @@ private Object findGuestJava() throws IllegalStateException { } guestJava = null; var envJava = System.getenv("ENSO_JAVA"); + if (envJava == null) { + return guestJava; + } if ("espresso".equals(envJava)) { var src = Source.newBuilder("java", "", "getbindings.java").build(); try { guestJava = environment.parsePublic(src).call(); + logger.log(Level.SEVERE, "Using experimental Espresso support!"); } catch (Exception ex) { if (ex.getMessage().contains("No language for id java found.")) { logger.log(Level.SEVERE, "Environment variable ENSO_JAVA=" + envJava + ", but " + ex.getMessage()); @@ -443,6 +474,8 @@ private Object findGuestJava() throws IllegalStateException { throw ise; } } + } else { + throw new IllegalStateException("Unsupported value of ENSO_JAVA environment variable: " + envJava); } return guestJava; } @@ -641,30 +674,6 @@ public NotificationHandler getNotificationHandler() { return notificationHandler; } - private Object getNestedClass(Object hostClass, List nestedClassName) { - Object nestedClass = hostClass; - var interop = InteropLibrary.getUncached(); - for (String name : nestedClassName) { - if (interop.isMemberReadable(nestedClass, name)) { - Object member; - try { - member = interop.readMember(nestedClass, name); - } catch (UnsupportedMessageException | UnknownIdentifierException e) { - throw new IllegalStateException(e); - } - assert member != null; - if (interop.isMetaObject(member)) { - nestedClass = member; - } else { - return null; - } - } else { - return null; - } - } - return nestedClass; - } - private T getOption(OptionKey key) { var options = getEnvironment().getOptions(); var safely = false; diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala index 413a8b9bd57e..9fceeb762e4c 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala @@ -181,7 +181,7 @@ private class DefaultPackageRepository( isLibrary: Boolean ): Unit = { val extensions = pkg.listPolyglotExtensions("java") - extensions.foreach(context.getEnvironment.addToHostClassPath) + extensions.foreach(context.addToHostClassPath) val (regularModules, syntheticModulesMetadata) = pkg .listSources()