Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline Execution #8148

Merged
merged 24 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ class ExecuteExpressionHandler(
) =>
contextRegistry ! ContextRegistryProtocol.ExecuteExpression(
clientId,
params.executionContextId,
params.visualizationId,
params.expressionId,
params.visualizationConfig
params.expression
)
val cancellable =
context.system.scheduler.scheduleOnce(timeout, self, RequestTimeout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,13 @@ final class ContextRegistry(
sender() ! AccessDenied
}

case ExecuteExpression(clientId, visualizationId, expressionId, cfg) =>
val contextId = cfg.executionContextId
case ExecuteExpression(
clientId,
contextId,
visualizationId,
expressionId,
expression
) =>
if (store.hasContext(clientId, contextId)) {
store.getListener(contextId).foreach { listener =>
listener ! RegisterOneshotVisualization(
Expand All @@ -272,17 +277,18 @@ final class ContextRegistry(
)
}
val handler = context.actorOf(
AttachVisualizationHandler.props(
ExecuteExpressionHandler.props(
runtimeFailureMapper,
timeout,
runtime
)
)
handler.forward(
Api.AttachVisualization(
Api.ExecuteExpression(
contextId,
visualizationId,
expressionId,
cfg.toApi
expression
)
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.enso.languageserver.filemanager.{FileSystemFailure, Path}
import org.enso.languageserver.libraries.LibraryComponentGroup
import org.enso.languageserver.runtime.ExecutionApi.ContextId
import org.enso.languageserver.session.JsonSession
import org.enso.logger.masking.ToLogString
import org.enso.logger.masking.{MaskedString, ToLogString}
import org.enso.text.editing.model

import java.util.UUID
Expand Down Expand Up @@ -422,23 +422,23 @@ object ContextRegistryProtocol {
* @param clientId the requester id
* @param visualizationId an identifier of a visualization
* @param expressionId an identifier of an expression which is visualised
* @param visualizationConfig a configuration object for properties of the
* visualization
* @param expression the expression to execute
*/
case class ExecuteExpression(
clientId: ClientId,
executionContextId: UUID,
visualizationId: UUID,
expressionId: UUID,
visualizationConfig: VisualizationConfiguration
expression: String
) extends ToLogString {

/** @inheritdoc */
override def toLogString(shouldMask: Boolean): String =
"ExecuteExpression(" +
s"clientId=$clientId," +
s"visualizationId=$visualizationId," +
s"expressionId=$expressionId,visualizationConfig=" +
visualizationConfig.toLogString(shouldMask) +
s"expressionId=$expressionId,expression=" +
MaskedString(expression).toLogString(shouldMask) +
")"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ object VisualizationApi {
extends Method("executionContext/executeExpression") {

case class Params(
executionContextId: UUID,
visualizationId: UUID,
expressionId: UUID,
visualizationConfig: VisualizationConfiguration
expression: String
)

implicit val hasParams: HasParams.Aux[this.type, ExecuteExpression.Params] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.enso.languageserver.runtime.handler

import akka.actor.{Actor, ActorRef, Cancellable, Props}
import akka.pattern.pipe
import com.typesafe.scalalogging.LazyLogging
import org.enso.languageserver.requesthandler.RequestTimeout
import org.enso.languageserver.runtime.{
ContextRegistryProtocol,
RuntimeFailureMapper
}
import org.enso.languageserver.util.UnhandledLogging
import org.enso.polyglot.runtime.Runtime.Api

import java.util.UUID

import scala.concurrent.duration.FiniteDuration

/** A request handler for execute expression commands.
*
* @param runtimeFailureMapper mapper for runtime failures
* @param timeout request timeout
* @param runtime reference to the runtime connector
*/
class ExecuteExpressionHandler(
runtimeFailureMapper: RuntimeFailureMapper,
timeout: FiniteDuration,
runtime: ActorRef
) extends Actor
with LazyLogging
with UnhandledLogging {

import context.dispatcher

override def receive: Receive = requestStage

private def requestStage: Receive = { case msg: Api.ExecuteExpression =>
runtime ! Api.Request(UUID.randomUUID(), msg)
val cancellable =
context.system.scheduler.scheduleOnce(timeout, self, RequestTimeout)
context.become(responseStage(sender(), cancellable))
}

private def responseStage(
replyTo: ActorRef,
cancellable: Cancellable
): Receive = {
case RequestTimeout =>
replyTo ! RequestTimeout
context.stop(self)

case Api.Response(_, Api.VisualizationAttached()) =>
replyTo ! ContextRegistryProtocol.VisualizationAttached
cancellable.cancel()
context.stop(self)

case Api.Response(_, error: Api.Error) =>
runtimeFailureMapper.mapApiError(error).pipeTo(replyTo)
cancellable.cancel()
context.stop(self)
}

}

object ExecuteExpressionHandler {

/** Creates configuration object used to create a [[ExecuteExpressionHandler]].
*
* @param runtimeFailureMapper mapper for runtime failures
* @param timeout request timeout
* @param runtime reference to the runtime connector
*/
def props(
runtimeFailureMapper: RuntimeFailureMapper,
timeout: FiniteDuration,
runtime: ActorRef
): Props =
Props(
new ExecuteExpressionHandler(runtimeFailureMapper, timeout, runtime)
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.enso.polyglot.debugger;

import java.util.UUID;

public record ExecutedVisualization(
Object result,
Throwable error,
UUID visualizationId,
UUID expressionId,
Object expressionValue) {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface IdExecutionService {
String INSTRUMENT_ID = "id-value-extractor";

public interface Callbacks {

/**
* Finds out previously computed result for given id. If a result is returned, then the
* execution of given node is skipped and the value is returned back.
Expand All @@ -18,12 +19,12 @@ public interface Callbacks {
* @return {@code null} should the execution of the node be performed; any other value to skip
* the execution and return the value as a result.
*/
Object findCachedResult(UUID nodeId);
Object findCachedResult(Object materializedFrame, Object node, UUID nodeId);

/**
* Notifies when an execution of a node is over.
*
* @param nodeId identification of the node to be computed
* @param nodeId expression node id that has been computed
* @param result the just computed result
* @param isPanic was the result a panic?
* @param nanoElapsedTime how long it took to compute the result?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ object Runtime {
value = classOf[Api.AttachVisualization],
name = "attachVisualization"
),
new JsonSubTypes.Type(
value = classOf[Api.ExecuteExpression],
name = "executeExpression"
),
new JsonSubTypes.Type(
value = classOf[Api.VisualizationAttached],
name = "visualizationAttached"
Expand Down Expand Up @@ -1553,6 +1557,13 @@ object Runtime {
*/
final case class InitializedNotification() extends ApiResponse

final case class ExecuteExpression(
contextId: ContextId,
visualizationId: VisualizationId,
expressionId: ExpressionId,
expression: String
) extends ApiRequest

/** A request sent from the client to the runtime server, to create a new
* visualization for an expression identified by `expressionId`.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Compiler(
private val importResolver: ImportResolver = new ImportResolver(this)
private val irCachingEnabled = !context.isIrCachingDisabled
private val useGlobalCacheLocations = context.isUseGlobalCacheLocations
private val isInteractiveMode = context.isInteractiveMode()
private val isInteractiveMode = context.isInteractiveMode
private val output: PrintStream =
if (config.outputRedirect.isDefined)
new PrintStream(config.outputRedirect.get)
Expand Down Expand Up @@ -112,7 +112,7 @@ class Compiler(
}

/** @return the package repository instance. */
def getPackageRepository(): PackageRepository =
def getPackageRepository: PackageRepository =
context.getPackageRepository

/** Processes the provided language sources, registering any bindings in the
Expand Down Expand Up @@ -142,7 +142,7 @@ class Compiler(
shouldCompileDependencies: Boolean,
useGlobalCacheLocations: Boolean
): Future[java.lang.Boolean] = {
getPackageRepository().getMainProjectPackage match {
getPackageRepository.getMainProjectPackage match {
case None =>
context.log(
Level.SEVERE,
Expand Down Expand Up @@ -269,7 +269,7 @@ class Compiler(
) {
val importedModulesLoadedFromSource = importedModules
.filter(isLoadedFromSource)
.map(context.getModuleName(_))
.map(context.getModuleName)
context.log(
Compiler.defaultLogLevel,
"{0} imported module caches were invalided, forcing invalidation of {1}. [{2}]",
Expand All @@ -279,7 +279,7 @@ class Compiler(
importedModulesLoadedFromSource.take(10).mkString("", ",", "...")
)
)
context.updateModule(module, _.invalidateCache)
context.updateModule(module, _.invalidateCache())
parseModule(module)
runImportsAndExportsResolution(module, generateCode)
} else {
Expand Down Expand Up @@ -458,9 +458,9 @@ class Compiler(
private def isModuleInRootPackage(module: Module): Boolean = {
if (!context.isInteractive(module)) {
val pkg = PackageRepositoryUtils
.getPackageOf(getPackageRepository(), module.getSourceFile)
.getPackageOf(getPackageRepository, module.getSourceFile)
.toScala
pkg.contains(getPackageRepository().getMainProjectPackage.get)
pkg.contains(getPackageRepository.getMainProjectPackage.get)
} else false
}

Expand Down Expand Up @@ -573,7 +573,7 @@ class Compiler(
"Parsing module [{0}].",
context.getModuleName(module)
)
context.updateModule(module, _.resetScope)
context.updateModule(module, _.resetScope())

if (irCachingEnabled && !context.isInteractive(module)) {
if (context.deserializeModule(this, module)) {
Expand Down Expand Up @@ -604,7 +604,7 @@ class Compiler(
"Loading module [{0}] from source.",
context.getModuleName(module)
)
context.updateModule(module, _.resetScope)
context.updateModule(module, _.resetScope())

val moduleContext = ModuleContext(
module = module,
Expand Down Expand Up @@ -695,10 +695,10 @@ class Compiler(
.build()
val tree = ensoCompiler.parse(source.getCharacters)

ensoCompiler.generateIRInline(tree).flatMap { ir =>
ensoCompiler.generateIRInline(tree).map { ir =>
val compilerOutput = runCompilerPhasesInline(ir, newContext)
runErrorHandlingInline(compilerOutput, source, newContext)
Some((newContext, compilerOutput, source))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing flatMap and then Some is strange. map is better.

(newContext, compilerOutput, source)
}
}

Expand Down Expand Up @@ -743,14 +743,6 @@ class Compiler(
def parseInline(source: Source): Tree =
ensoCompiler.parse(source.getCharacters())

/** Parses the metadata of the provided language sources.
*
* @param source the code to parse
* @return the source metadata
*/
// def parseMeta(source: CharSequence): IDMap =
// Parser().splitMeta(source.toString)._2

/** Enhances the provided IR with import/export statements for the provided list
* of fully qualified names of modules. The statements are considered to be "synthetic" i.e. compiler-generated.
* That way one can access modules using fully qualified names.
Expand Down Expand Up @@ -859,7 +851,7 @@ class Compiler(
* for inline evaluation
* @return the output result of the
*/
def runCompilerPhasesInline(
private def runCompilerPhasesInline(
ir: Expression,
inlineContext: InlineContext
): Expression = {
Expand All @@ -873,12 +865,12 @@ class Compiler(
* @param source the original source code.
* @param inlineContext the inline compilation context.
*/
def runErrorHandlingInline(
private def runErrorHandlingInline(
ir: Expression,
source: Source,
inlineContext: InlineContext
): Unit =
if (config.isStrictErrors) {
if (inlineContext.compilerConfig.isStrictErrors) {
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
val errors = GatherDiagnostics
.runExpression(ir, inlineContext)
.unsafeGetMetadata(
Expand All @@ -896,7 +888,7 @@ class Compiler(
*
* @param modules the modules to check against errors
*/
def runErrorHandling(
private def runErrorHandling(
modules: List[Module]
): Unit = {
if (config.isStrictErrors) {
Expand All @@ -922,7 +914,7 @@ class Compiler(
* @param module the module for which to gather diagnostics
* @return the diagnostics from the module
*/
def gatherDiagnostics(module: Module): List[Diagnostic] = {
private def gatherDiagnostics(module: Module): List[Diagnostic] = {
GatherDiagnostics
.runModule(
context.getIr(module),
Expand Down
Loading
Loading