diff --git a/build.sbt b/build.sbt index 376750f3e3..0571c2f2ca 100644 --- a/build.sbt +++ b/build.sbt @@ -1230,6 +1230,7 @@ lazy val `runtime-language-epb` = truffleDslSuppressWarnsSetting, instrumentationSettings ) + .dependsOn(`polyglot-api`) /** Runs gu (GraalVM updater) command with given `args`. * For example `runGu(Seq("install", "js"))`. @@ -1404,7 +1405,6 @@ lazy val runtime = (project in file("engine/runtime")) Benchmark / parallelExecution := false ) .dependsOn(`common-polyglot-core-utils`) - .dependsOn(`runtime-language-epb`) .dependsOn(`edition-updater`) .dependsOn(`interpreter-dsl`) .dependsOn(`library-manager`) @@ -1532,6 +1532,7 @@ lazy val `runtime-with-instruments` = .dependsOn(`runtime-instrument-id-execution`) .dependsOn(`runtime-instrument-repl-debugger`) .dependsOn(`runtime-instrument-runtime-server`) + .dependsOn(`runtime-language-epb`) /* runtime-with-polyglot * ~~~~~~~~~~~~~~~~~~~~~ diff --git a/engine/polyglot-api/src/main/java/org/enso/polyglot/ForeignLanguage.java b/engine/polyglot-api/src/main/java/org/enso/polyglot/ForeignLanguage.java new file mode 100644 index 0000000000..857ded4a7e --- /dev/null +++ b/engine/polyglot-api/src/main/java/org/enso/polyglot/ForeignLanguage.java @@ -0,0 +1,47 @@ +package org.enso.polyglot; + +import com.oracle.truffle.api.source.Source; +import java.util.Arrays; + +/** Lists all the languages supported in polyglot eval. */ +public enum ForeignLanguage { + JS("js", "js"), + PY("python", "python"), + R("R", "r"); + + public static final String ID = "epb"; + + private final String truffleId; + private final String syntacticTag; + + ForeignLanguage(String truffleId, String syntacticTag) { + this.truffleId = truffleId; + this.syntacticTag = syntacticTag; + } + + /** @return a Truffle language ID associated with this language */ + public String getTruffleId() { + return truffleId; + } + + /** + * Transforms an Enso-side syntactic language tag into a recognized language object. + * + * @param tag the tag to parse + * @return a corresponding language value, or null if the language is not recognized + */ + public static ForeignLanguage getBySyntacticTag(String tag) { + return Arrays.stream(values()).filter(l -> l.syntacticTag.equals(tag)).findFirst().orElse(null); + } + + /** + * Builds a new source instance that can later be parsed by this class. + * + * @param foreignSource the foreign source to evaluate + * @param name the name of the source + * @return a source instance, parsable by the EPB language + */ + public Source buildSource(String foreignSource, String name) { + return Source.newBuilder(ID, this + "#" + foreignSource, name).build(); + } +} diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbLanguage.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbLanguage.java index b2829f661f..a5306ed746 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbLanguage.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbLanguage.java @@ -5,6 +5,7 @@ import com.oracle.truffle.api.TruffleLanguage; import java.util.function.Consumer; import org.enso.interpreter.epb.node.ContextRewrapNode; import org.enso.interpreter.epb.node.ForeignEvalNode; +import org.enso.polyglot.ForeignLanguage; /** * An internal language that serves as a bridge between Enso and other supported languages. @@ -29,7 +30,7 @@ import org.enso.interpreter.epb.node.ForeignEvalNode; * provide context-switching facilities. */ @TruffleLanguage.Registration( - id = EpbLanguage.ID, + id = ForeignLanguage.ID, name = "Enso Polyglot Bridge", characterMimeTypes = {EpbLanguage.MIME}, internal = true, @@ -37,7 +38,6 @@ import org.enso.interpreter.epb.node.ForeignEvalNode; contextPolicy = TruffleLanguage.ContextPolicy.SHARED, services = Consumer.class) public class EpbLanguage extends TruffleLanguage { - public static final String ID = "epb"; public static final String MIME = "application/epb"; @Override diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbParser.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbParser.java index 0fd9e706ca..21c4ca625f 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbParser.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/EpbParser.java @@ -1,45 +1,10 @@ package org.enso.interpreter.epb; import com.oracle.truffle.api.source.Source; -import java.util.Arrays; +import org.enso.polyglot.ForeignLanguage; /** A class containing helpers for creating and parsing EPB code */ public class EpbParser { - private static final String separator = "#"; - - /** Lists all the languages supported in polyglot eval. */ - public enum ForeignLanguage { - JS("js", "js"), - PY("python", "python"), - R("R", "r"); - - private final String truffleId; - private final String syntacticTag; - - ForeignLanguage(String truffleId, String syntacticTag) { - this.truffleId = truffleId; - this.syntacticTag = syntacticTag; - } - - /** @return a Truffle language ID associated with this language */ - public String getTruffleId() { - return truffleId; - } - - /** - * Transforms an Enso-side syntactic language tag into a recognized language object. - * - * @param tag the tag to parse - * @return a corresponding language value, or null if the language is not recognized - */ - public static ForeignLanguage getBySyntacticTag(String tag) { - return Arrays.stream(values()) - .filter(l -> l.syntacticTag.equals(tag)) - .findFirst() - .orElse(null); - } - } - /** A parsing result. */ public static class Result { private final ForeignLanguage language; @@ -69,19 +34,7 @@ public class EpbParser { */ public static Result parse(Source source) { String src = source.getCharacters().toString(); - String[] langAndCode = src.split(separator, 2); + String[] langAndCode = src.split("#", 2); return new Result(ForeignLanguage.valueOf(langAndCode[0]), langAndCode[1]); } - - /** - * Builds a new source instance that can later be parsed by this class. - * - * @param language the foreign language to use - * @param foreignSource the foreign source to evaluate - * @param name the name of the source - * @return a source instance, parsable by the EPB language - */ - public static Source buildSource(ForeignLanguage language, String foreignSource, String name) { - return Source.newBuilder(EpbLanguage.ID, language + separator + foreignSource, name).build(); - } } diff --git a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/ForeignEvalNode.java b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/ForeignEvalNode.java index d0a84e752d..68954d335f 100644 --- a/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/ForeignEvalNode.java +++ b/engine/runtime-language-epb/src/main/java/org/enso/interpreter/epb/node/ForeignEvalNode.java @@ -17,7 +17,6 @@ import org.enso.interpreter.epb.EpbLanguage; import org.enso.interpreter.epb.EpbParser; import org.enso.interpreter.epb.runtime.ForeignParsingException; import org.enso.interpreter.epb.runtime.GuardedTruffleContext; -import org.graalvm.polyglot.Context; public class ForeignEvalNode extends RootNode { private final EpbParser.Result code; @@ -72,7 +71,8 @@ public class ForeignEvalNode extends RootNode { CompilerDirectives.transferToInterpreterAndInvalidate(); var foreignLang = code.getLanguage(); String truffleLangId = foreignLang.getTruffleId(); - var installedLanguages = Context.getCurrent().getEngine().getLanguages(); + var context = EpbContext.get(this); + var installedLanguages = context.getEnv().getInternalLanguages(); if (!installedLanguages.containsKey(truffleLangId)) { this.parseException = new ForeignParsingException(truffleLangId, installedLanguages.keySet(), this); diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java b/engine/runtime-with-polyglot/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java similarity index 96% rename from engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java rename to engine/runtime-with-polyglot/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java index 6e7af79eb8..32ea800719 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java +++ b/engine/runtime-with-polyglot/src/test/java/org/enso/interpreter/test/ForeignMethodInvokeTest.java @@ -13,7 +13,7 @@ public class ForeignMethodInvokeTest extends TestBase { @BeforeClass public static void prepareCtx() { - ctx = createDefaultContext(); + ctx = defaultContextBuilder("enso").build(); } @AfterClass @@ -27,10 +27,10 @@ public class ForeignMethodInvokeTest extends TestBase { // should fail with a Polyglot_Error, rather than crashing whole engine. String source = """ from Standard.Base import all - + foreign python py_array = \"\"\" return [1,2,3] - + main = Panic.recover Any py_array """.trim(); diff --git a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java index 240a12cd77..24c27eb309 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/EnsoLanguage.java @@ -15,7 +15,6 @@ import org.enso.distribution.DistributionManager; import org.enso.distribution.Environment; import org.enso.distribution.locking.LockManager; import org.enso.distribution.locking.ThreadSafeFileLockManager; -import org.enso.interpreter.epb.EpbLanguage; import org.enso.interpreter.instrument.NotificationHandler; import org.enso.interpreter.instrument.NotificationHandler.Forwarder; import org.enso.interpreter.instrument.NotificationHandler.TextMode$; @@ -31,6 +30,7 @@ import org.enso.interpreter.runtime.tag.Patchable; import org.enso.interpreter.util.FileDetector; import org.enso.lockmanager.client.ConnectedLockManager; import org.enso.logger.masking.MaskingFactory; +import org.enso.polyglot.ForeignLanguage; import org.enso.polyglot.LanguageInfo; import org.enso.polyglot.RuntimeOptions; import org.enso.syntax2.Line; @@ -69,7 +69,7 @@ import com.oracle.truffle.api.nodes.RootNode; defaultMimeType = LanguageInfo.MIME_TYPE, characterMimeTypes = {LanguageInfo.MIME_TYPE}, contextPolicy = TruffleLanguage.ContextPolicy.EXCLUSIVE, - dependentLanguages = {EpbLanguage.ID}, + dependentLanguages = {ForeignLanguage.ID}, fileTypeDetectors = FileDetector.class, services= { Timer.class, NotificationHandler.Forwarder.class, LockManager.class } ) @@ -159,7 +159,7 @@ public final class EnsoLanguage extends TruffleLanguage { var env = context.getEnvironment(); var preinit = env.getOptions().get(RuntimeOptions.PREINITIALIZE_KEY); if (preinit != null && preinit.length() > 0) { - var epb = env.getInternalLanguages().get(EpbLanguage.ID); + var epb = env.getInternalLanguages().get(ForeignLanguage.ID); var run = env.lookup(epb, Consumer.class); run.accept(preinit); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java index d9538ec19c..f53b3b8d54 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/generic/ReadArrayElementNode.java @@ -7,8 +7,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import org.enso.interpreter.Constants; import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.epb.node.CoercePrimitiveNode; -import org.enso.interpreter.node.expression.foreign.CoerceNothing; +import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode; import org.enso.interpreter.runtime.EnsoContext; import org.enso.interpreter.runtime.builtin.Builtins; import org.enso.interpreter.runtime.error.PanicException; @@ -22,13 +21,12 @@ public class ReadArrayElementNode extends Node { private @Child InteropLibrary library = InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH); - private @Child CoercePrimitiveNode coercion = CoercePrimitiveNode.build(); - private @Child CoerceNothing nothingCoercion = CoerceNothing.build(); + private @Child HostValueToEnsoNode toEnso = HostValueToEnsoNode.build(); private final BranchProfile err = BranchProfile.create(); Object execute(Object array, long index) { try { - return nothingCoercion.execute(coercion.execute(library.readArrayElement(array, index))); + return toEnso.execute(library.readArrayElement(array, index)); } catch (UnsupportedMessageException e) { err.enter(); Builtins builtins = EnsoContext.get(this).getBuiltins(); diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index 331ccd08d8..99266e67ab 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -31,7 +31,7 @@ import org.enso.compiler.pass.resolve.{ TypeNames, TypeSignatures } -import org.enso.interpreter.epb.EpbParser +import org.enso.polyglot.ForeignLanguage import org.enso.interpreter.node.callable.argument.ReadArgumentNode import org.enso.interpreter.node.callable.function.{ BlockNode, @@ -1684,7 +1684,7 @@ class IrToTruffle( val bodyExpr = body match { case IR.Foreign.Definition(lang, code, _, _, _) => buildForeignBody( - EpbParser.ForeignLanguage.getBySyntacticTag(lang), + ForeignLanguage.getBySyntacticTag(lang), code, arguments.map(_.name.name), argSlotIdxs @@ -1746,12 +1746,12 @@ class IrToTruffle( } private def buildForeignBody( - language: EpbParser.ForeignLanguage, + language: ForeignLanguage, code: String, argumentNames: List[String], argumentSlotIdxs: List[Int] ): RuntimeExpression = { - val src = EpbParser.buildSource(language, code, scopeName) + val src = language.buildSource(code, scopeName) val foreignCt = context.getEnvironment .parseInternal(src, argumentNames: _*) val argumentReaders = argumentSlotIdxs diff --git a/engine/runtime/src/main/scala/org/enso/compiler/pass/desugar/GenerateMethodBodies.scala b/engine/runtime/src/main/scala/org/enso/compiler/pass/desugar/GenerateMethodBodies.scala index a89881b64c..6119efbab2 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/pass/desugar/GenerateMethodBodies.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/pass/desugar/GenerateMethodBodies.scala @@ -12,8 +12,7 @@ import org.enso.compiler.pass.analyse.{ } import org.enso.compiler.pass.lint.UnusedBindings import org.enso.compiler.pass.optimise.LambdaConsolidate -import org.enso.interpreter.epb.EpbParser -import org.enso.interpreter.epb.EpbParser.ForeignLanguage +import org.enso.polyglot.ForeignLanguage import scala.annotation.{tailrec} @@ -299,7 +298,7 @@ case object GenerateMethodBodies extends IRPass { @tailrec private def findForeignDefinition( body: IR.Expression, - lang: Option[EpbParser.ForeignLanguage] + lang: Option[ForeignLanguage] ): Option[IR.Foreign.Definition] = { body match { case foreignDef: IR.Foreign.Definition => diff --git a/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java b/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java index ff92b96be3..e3f9575a2e 100644 --- a/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java +++ b/engine/runtime/src/test/java/org/enso/interpreter/test/TestBase.java @@ -39,8 +39,8 @@ public abstract class TestBase { return context; } - protected static Context.Builder defaultContextBuilder() { - return Context.newBuilder() + protected static Context.Builder defaultContextBuilder(String... languages) { + return Context.newBuilder(languages) .allowExperimentalOptions(true) .allowIO(IOAccess.ALL) .allowAllAccess(true)