From 8c5089d6b89f544da9dac48ef5c922be6bd9760b Mon Sep 17 00:00:00 2001 From: Kolya Opahle Date: Wed, 29 Jan 2020 15:08:16 +0100 Subject: [PATCH 1/3] use nested context for each example --- .../tools/lsp/server/LanguageServerImpl.java | 65 +-- .../tools/lsp/server/TruffleAdapter.java | 4 + .../server/request/SourceCodeEvaluator.java | 459 ++++++++++-------- 3 files changed, 304 insertions(+), 224 deletions(-) diff --git a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java index d6a09bbb058b..002f8f58c8e9 100644 --- a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java +++ b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java @@ -31,12 +31,7 @@ import java.net.Socket; import java.net.SocketAddress; import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -47,6 +42,7 @@ import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import com.oracle.truffle.api.CallTarget; import org.graalvm.collections.Pair; @@ -344,34 +340,39 @@ private void extractAndEvaluateExamples(URI uri, String sourceCode) { openedFileUri2Examples.put(uri, exampleDefinitions); - Future> evaluatedExamplesFuture = truffleAdapter.evaluateExamplesAndProbes(uri, exampleDefinitions); - Supplier> evaluatedExamplesSupplier = () -> waitForResultAndHandleExceptions(evaluatedExamplesFuture, new ArrayList<>()); - List evaluatedExamples = evaluatedExamplesSupplier.get(); - - ArrayList decorations = new ArrayList<>(); - - for (ExampleDefinition example : evaluatedExamples) { - for (ProbeDefinition probe : example.getProbes()) { - decorations.add(Decoration.create( - Range.create( - Position.create(probe.getLine(), probe.getStartColumn()), - Position.create(probe.getLine(), probe.getEndColumn()) - ), - probe.getResult().toString(), - "probeResult" - )); - } - decorations.add(Decoration.create( - Range.create( - Position.create(example.getExampleDefinitionLine(), 0), - Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) - ), - example.getExampleResult().toString(), - "exampleResult" - )); + List> futures = new LinkedList<>(); + + for (ExampleDefinition exampleDefinition : exampleDefinitions) { + futures.add(CompletableFuture.supplyAsync(() -> waitForResultAndHandleExceptions(truffleAdapter.evaluateExampleAndProbes(uri, exampleDefinition)))); } - client.publishDecorations(PublishDecorationsParams.create(uri.toString(), decorations)); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(ignored -> futures.stream() + .map(CompletableFuture::join) + .flatMap(example -> { + ArrayList decorations = new ArrayList<>(); + for (ProbeDefinition probe : example.getProbes()) { + decorations.add(Decoration.create( + Range.create( + Position.create(probe.getLine(), probe.getStartColumn()), + Position.create(probe.getLine(), probe.getEndColumn()) + ), + probe.getResult().toString(), + "probeResult" + )); + } + decorations.add(Decoration.create( + Range.create( + Position.create(example.getExampleDefinitionLine(), 0), + Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) + ), + example.getExampleResult().toString(), + "exampleResult" + )); + return decorations.stream(); + }).collect(Collectors.toList()) + ) + .thenAccept(decorations -> client.publishDecorations(PublishDecorationsParams.create(uri.toString(), decorations))); } private String buildExampleStringFromArgs(Boolean functionAlreadyHasExamples, int indexOfNewlyCreatedExamples, JSONObject inputMappingObject) { diff --git a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/TruffleAdapter.java b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/TruffleAdapter.java index cef635d814ba..14c12f9dc6aa 100644 --- a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/TruffleAdapter.java +++ b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/TruffleAdapter.java @@ -165,6 +165,10 @@ public Future> evaluateExamplesAndProbes(URI uri, List sourceCodeEvaluator.evaluateExamplesAndProbes(uri, examples)); } + public Future evaluateExampleAndProbes(URI uri, ExampleDefinition example) { + return contextAwareExecutor.executeWithNestedContext(() -> sourceCodeEvaluator.evaluateExampleAndProbes(uri, example)); + } + /** * Special handling needed, because some LSP clients send a MIME type as langId. * diff --git a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/request/SourceCodeEvaluator.java b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/request/SourceCodeEvaluator.java index 8b1c7d38fd86..e18b96115ba1 100644 --- a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/request/SourceCodeEvaluator.java +++ b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/request/SourceCodeEvaluator.java @@ -24,50 +24,40 @@ */ package org.graalvm.tools.lsp.server.request; -import java.io.IOException; -import java.net.URI; -import java.util.*; -import java.util.logging.Level; -import java.util.regex.Matcher; - import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.*; +import com.oracle.truffle.api.instrumentation.SourceSectionFilter.Builder; +import com.oracle.truffle.api.instrumentation.SourceSectionFilter.IndexRange; import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.nodes.ExecutableNode; +import com.oracle.truffle.api.nodes.LanguageInfo; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeVisitor; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; import org.graalvm.tools.lsp.definitions.ExampleDefinition; import org.graalvm.tools.lsp.definitions.LanguageAgnosticFunctionArgumentDefinition; import org.graalvm.tools.lsp.definitions.LanguageAgnosticFunctionDeclarationDefinition; import org.graalvm.tools.lsp.definitions.ProbeDefinition; -import org.graalvm.tools.lsp.server.ContextAwareExecutor; import org.graalvm.tools.lsp.exceptions.DiagnosticsNotification; import org.graalvm.tools.lsp.exceptions.EvaluationResultException; import org.graalvm.tools.lsp.exceptions.InvalidCoverageScriptURI; import org.graalvm.tools.lsp.exceptions.UnknownLanguageException; import org.graalvm.tools.lsp.instrument.LSPInstrument; +import org.graalvm.tools.lsp.server.ContextAwareExecutor; import org.graalvm.tools.lsp.server.types.Diagnostic; import org.graalvm.tools.lsp.server.types.DiagnosticSeverity; import org.graalvm.tools.lsp.server.types.Range; -import org.graalvm.tools.lsp.server.utils.CoverageData; -import org.graalvm.tools.lsp.server.utils.CoverageEventNode; -import org.graalvm.tools.lsp.server.utils.EvaluationResult; -import org.graalvm.tools.lsp.server.utils.InteropUtils; -import org.graalvm.tools.lsp.server.utils.RunScriptUtils; -import org.graalvm.tools.lsp.server.utils.SourcePredicateBuilder; -import org.graalvm.tools.lsp.server.utils.SourceUtils; -import org.graalvm.tools.lsp.server.utils.SourceWrapper; -import org.graalvm.tools.lsp.server.utils.TextDocumentSurrogate; -import org.graalvm.tools.lsp.server.utils.TextDocumentSurrogateMap; +import org.graalvm.tools.lsp.server.utils.*; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.frame.FrameSlot; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.instrumentation.SourceSectionFilter.Builder; -import com.oracle.truffle.api.instrumentation.SourceSectionFilter.IndexRange; -import com.oracle.truffle.api.nodes.ExecutableNode; -import com.oracle.truffle.api.nodes.LanguageInfo; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeVisitor; -import com.oracle.truffle.api.source.Source; -import com.oracle.truffle.api.source.SourceSection; +import java.io.IOException; +import java.net.URI; +import java.util.*; +import java.util.logging.Level; +import java.util.regex.Matcher; public final class SourceCodeEvaluator extends AbstractRequestHandler { private static final TruffleLogger LOG = TruffleLogger.getLogger(LSPInstrument.ID, SourceCodeEvaluator.class); @@ -77,6 +67,86 @@ public SourceCodeEvaluator(TruffleInstrument.Env env, TextDocumentSurrogateMap s super(env, surrogateMap, executor); } + private static EvaluationResult evalLiteral(Node nearestNode) { + Object nodeObject = ((InstrumentableNode) nearestNode).getNodeObject(); + if (nodeObject instanceof TruffleObject) { + try { + if (INTEROP.isMemberReadable(nodeObject, "literal")) { + Object result = INTEROP.readMember(nodeObject, "literal"); + if (result instanceof TruffleObject || InteropUtils.isPrimitive(result)) { + return EvaluationResult.createResult(result); + } else { + LOG.log(Level.FINE, "Literal is no TruffleObject or primitive: {0}", result.getClass()); + } + } + } catch (UnknownIdentifierException | UnsupportedMessageException e) { + LOG.warning(e.getMessage()); + return EvaluationResult.createError(e); + } + } + return EvaluationResult.createEvaluationSectionNotReached(); + } + + private static String findLanguageOfTestFile(URI runScriptUri, String fallbackLangId) { + try { + return Source.findLanguage(runScriptUri.toURL()); + } catch (IOException e) { + return fallbackLangId; + } + } + + /** + * A special method to create a {@link SourceSectionFilter} which filters for a specific source + * section during source code evaluation. We cannot simply filter with + * {@link Builder#sourceIs(Source...)} and {@link Builder#sourceSectionEquals(SourceSection...)} + * , because we are possibly not the creator of the Source and do not know which properties are + * set. The source which is evaluated could have been created by the language. For example by a + * Python import statement. Therefore we need to filter via URI (or name if the URI is a + * generated truffle-schema-URI). + * + * @param uri to filter sources for + * @param sourceSection to filter for with same start and end indices + * @return a builder to add further filter options + */ + static SourceSectionFilter.Builder createSourceSectionFilter(URI uri, SourceSection sourceSection) { + return SourceSectionFilter.newBuilder() // + .lineStartsIn(IndexRange.between(sourceSection.getStartLine(), sourceSection.getStartLine() + 1)) // + .lineEndsIn(IndexRange.between(sourceSection.getEndLine(), sourceSection.getEndLine() + 1)) // + .columnStartsIn(IndexRange.between(sourceSection.getStartColumn(), sourceSection.getStartColumn() + 1)) // + .columnEndsIn(IndexRange.between(sourceSection.getEndColumn(), sourceSection.getEndColumn() + 1)) // + .sourceIs(SourcePredicateBuilder.newBuilder().uriOrTruffleName(uri).build()); + } + + static List findCoverageDataBeforeNode(TextDocumentSurrogate surrogate, Node targetNode) { + List coveragesBeforeNode = new ArrayList<>(); + targetNode.getRootNode().accept(new NodeVisitor() { + boolean found = false; + + @Override + public boolean visit(Node node) { + if (found) { + return false; + } + + if (node.equals(targetNode)) { + found = true; + return false; + } + + SourceSection sourceSection = node.getSourceSection(); + if (sourceSection != null && sourceSection.isAvailable()) { + List coverageData = surrogate.getCoverageData(sourceSection); + if (coverageData != null) { + coveragesBeforeNode.addAll(coverageData); + } + } + + return true; + } + }); + return coveragesBeforeNode; + } + private Map getFunctionDeclarations(SourceSectionFilter.SourcePredicate srcPredicate, URI uri) { Map functionDeclarations = new HashMap<>(); SourceSectionFilter filter = SourceSectionFilter.newBuilder().sourceIs(srcPredicate).build(); @@ -142,7 +212,7 @@ public CallTarget parse(final TextDocumentSurrogate surrogate) throws Diagnostic } catch (Exception e) { if (e instanceof TruffleException) { throw DiagnosticsNotification.create(surrogate.getUri(), - Diagnostic.create(SourceUtils.getRangeFrom((TruffleException) e), e.getMessage(), DiagnosticSeverity.Error, null, "Graal", null)); + Diagnostic.create(SourceUtils.getRangeFrom((TruffleException) e), e.getMessage(), DiagnosticSeverity.Error, null, "Graal", null)); } else { // TODO(ds) throw an Exception which the LSPServer can catch to send a client // notification @@ -242,6 +312,91 @@ public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwa return examples; } + public ExampleDefinition evaluateExampleAndProbes(URI uri, ExampleDefinition example) throws DiagnosticsNotification { + TextDocumentSurrogate originalSurrogate = surrogateMap.get(uri); + + TextDocumentSurrogate surrogate = originalSurrogate.copy(); + surrogate.setEditorText(surrogate.getEditorText() + "\n" + example.getFunctionName()); + final CallTarget callTarget = parse(surrogate); + + List> eventBindingList = new ArrayList<>(); + + if (example.getProbeAll()) { + SourceSectionFilter sourceSectionFilter = SourceSectionFilter. + newBuilder(). + tagIs(StandardTags.StatementTag.class). + build(); + eventBindingList.add(env.getInstrumenter().attachExecutionEventListener(sourceSectionFilter, new ExecutionEventListener() { + @Override + public void onEnter(EventContext context, VirtualFrame frame) { + // Do nothing + } + + @Override + public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { + SourceSection sourceSection = context.getInstrumentedSourceSection(); + ProbeDefinition probe = new ProbeDefinition(sourceSection.getStartLine()); + + example.getProbes().add(probe); + + probe.setResult(result); + probe.setUri(sourceSection.getSource().getName()); + probe.setStartColumn(sourceSection.getStartColumn() + 1); + probe.setEndColumn(sourceSection.getEndColumn() + 1); + } + + @Override + public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { + // Do nothing + } + })); + } else { + for (ProbeDefinition probe : example.getProbes()) { + int line = probe.getLine(); + + SourceSectionFilter sourceSectionFilter = SourceSectionFilter. + newBuilder(). + tagIs(StandardTags.StatementTag.class). + build(); + + eventBindingList.add(env.getInstrumenter().attachExecutionEventListener(sourceSectionFilter, new ExecutionEventListener() { + @Override + public void onEnter(EventContext context, VirtualFrame frame) { + // Do nothing + } + + @Override + public void onReturnValue(EventContext context, VirtualFrame frame, Object result) { + SourceSection sourceSection = context.getInstrumentedSourceSection(); + + probe.setResult(result); + probe.setUri(sourceSection.getSource().getName()); + probe.setStartColumn(sourceSection.getStartColumn() + 1); + probe.setEndColumn(sourceSection.getEndColumn() + 1); + } + + @Override + public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) { + // Do nothing + } + })); + + } + } + + Object exampleResult; + try { + exampleResult = callTarget.call(); + } catch (Exception e) { + exampleResult = e.getMessage(); + } + example.setExampleResult(exampleResult); + + eventBindingList.forEach(EventBinding::dispose); + + return example; + } + public EvaluationResult tryDifferentEvalStrategies(TextDocumentSurrogate surrogate, Node nearestNode) throws DiagnosticsNotification { LOG.fine("Trying literal eval..."); EvaluationResult literalResult = evalLiteral(nearestNode); @@ -268,26 +423,6 @@ public EvaluationResult tryDifferentEvalStrategies(TextDocumentSurrogate surroga return globalScopeEvalResult; } - private static EvaluationResult evalLiteral(Node nearestNode) { - Object nodeObject = ((InstrumentableNode) nearestNode).getNodeObject(); - if (nodeObject instanceof TruffleObject) { - try { - if (INTEROP.isMemberReadable(nodeObject, "literal")) { - Object result = INTEROP.readMember(nodeObject, "literal"); - if (result instanceof TruffleObject || InteropUtils.isPrimitive(result)) { - return EvaluationResult.createResult(result); - } else { - LOG.log(Level.FINE, "Literal is no TruffleObject or primitive: {0}", result.getClass()); - } - } - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - LOG.warning(e.getMessage()); - return EvaluationResult.createError(e); - } - } - return EvaluationResult.createEvaluationSectionNotReached(); - } - private EvaluationResult evalWithCoverageData(TextDocumentSurrogate textDocumentSurrogate, Node nearestNode) { if (!textDocumentSurrogate.hasCoverageData()) { return EvaluationResult.createEvaluationSectionNotReached(); @@ -341,7 +476,7 @@ public EvaluationResult runToSectionAndEval(final TextDocumentSurrogate surrogat } public EvaluationResult runToSectionAndEval(final TextDocumentSurrogate surrogate, final SourceSection sourceSection, SourceSectionFilter eventFilter, SourceSectionFilter inputFilter) - throws DiagnosticsNotification { + throws DiagnosticsNotification { Set coverageUris = surrogate.getCoverageUris(sourceSection); URI runScriptUriFallback = coverageUris == null ? null : coverageUris.stream().findFirst().orElseGet(() -> null); TextDocumentSurrogate surrogateOfTestFile = createSurrogateForTestFile(surrogate, runScriptUriFallback); @@ -349,90 +484,90 @@ public EvaluationResult runToSectionAndEval(final TextDocumentSurrogate surrogat final boolean isInputFilterDefined = inputFilter != null; EventBinding binding = env.getInstrumenter().attachExecutionEventFactory( - eventFilter, - inputFilter, - new ExecutionEventNodeFactory() { - StringBuilder indent = new StringBuilder(""); + eventFilter, + inputFilter, + new ExecutionEventNodeFactory() { + StringBuilder indent = new StringBuilder(""); + + @Override + public ExecutionEventNode create(EventContext context) { + return new ExecutionEventNode() { + + private String sourceSectionFormat(SourceSection section) { + return "SourceSection(" + section.getCharacters().toString().replaceAll("\n", Matcher.quoteReplacement("\\n")) + ")"; + } + + @Override + public void onReturnValue(VirtualFrame frame, Object result) { + if (LOG.isLoggable(Level.FINEST)) { + logOnReturnValue(result); + } + + if (!isInputFilterDefined) { + CompilerDirectives.transferToInterpreter(); + throw new EvaluationResultException(result); + } + } + + @TruffleBoundary + private void logOnReturnValue(Object result) { + if (indent.length() > 1) { + indent.setLength(indent.length() - 2); + } + LOG.log(Level.FINEST, "{0}onReturnValue {1} {2} {3} {4}", new Object[]{indent, context.getInstrumentedNode().getClass().getSimpleName(), + sourceSectionFormat(context.getInstrumentedSourceSection()), result}); + } + + @Override + public void onReturnExceptional(VirtualFrame frame, Throwable exception) { + if (LOG.isLoggable(Level.FINEST)) { + logOnReturnExceptional(); + } + } + + @TruffleBoundary + private void logOnReturnExceptional() { + indent.setLength(indent.length() - 2); + LOG.log(Level.FINEST, "{0}onReturnExceptional {1}", new Object[]{indent, sourceSectionFormat(context.getInstrumentedSourceSection())}); + } + + @Override + public void onEnter(VirtualFrame frame) { + if (LOG.isLoggable(Level.FINEST)) { + logOnEnter(); + } + } + + @TruffleBoundary + private void logOnEnter() { + LOG.log(Level.FINEST, "{0}onEnter {1} {2}", new Object[]{indent, context.getInstrumentedNode().getClass().getSimpleName(), + sourceSectionFormat(context.getInstrumentedSourceSection())}); + indent.append(" "); + } @Override - public ExecutionEventNode create(EventContext context) { - return new ExecutionEventNode() { - - private String sourceSectionFormat(SourceSection section) { - return "SourceSection(" + section.getCharacters().toString().replaceAll("\n", Matcher.quoteReplacement("\\n")) + ")"; - } - - @Override - public void onReturnValue(VirtualFrame frame, Object result) { - if (LOG.isLoggable(Level.FINEST)) { - logOnReturnValue(result); - } - - if (!isInputFilterDefined) { - CompilerDirectives.transferToInterpreter(); - throw new EvaluationResultException(result); - } - } - - @TruffleBoundary - private void logOnReturnValue(Object result) { - if (indent.length() > 1) { - indent.setLength(indent.length() - 2); - } - LOG.log(Level.FINEST, "{0}onReturnValue {1} {2} {3} {4}", new Object[]{indent, context.getInstrumentedNode().getClass().getSimpleName(), - sourceSectionFormat(context.getInstrumentedSourceSection()), result}); - } - - @Override - public void onReturnExceptional(VirtualFrame frame, Throwable exception) { - if (LOG.isLoggable(Level.FINEST)) { - logOnReturnExceptional(); - } - } - - @TruffleBoundary - private void logOnReturnExceptional() { - indent.setLength(indent.length() - 2); - LOG.log(Level.FINEST, "{0}onReturnExceptional {1}", new Object[]{indent, sourceSectionFormat(context.getInstrumentedSourceSection())}); - } - - @Override - public void onEnter(VirtualFrame frame) { - if (LOG.isLoggable(Level.FINEST)) { - logOnEnter(); - } - } - - @TruffleBoundary - private void logOnEnter() { - LOG.log(Level.FINEST, "{0}onEnter {1} {2}", new Object[]{indent, context.getInstrumentedNode().getClass().getSimpleName(), - sourceSectionFormat(context.getInstrumentedSourceSection())}); - indent.append(" "); - } - - @Override - public void onInputValue(VirtualFrame frame, EventContext inputContext, int inputIndex, Object inputValue) { - if (LOG.isLoggable(Level.FINEST)) { - logOnInputValue(inputContext, inputIndex, inputValue); - } - CompilerDirectives.transferToInterpreter(); - throw new EvaluationResultException(inputValue); - } - - @TruffleBoundary - private void logOnInputValue(EventContext inputContext, int inputIndex, Object inputValue) { - indent.setLength(indent.length() - 2); - LOG.log(Level.FINEST, "{0}onInputValue idx:{1} {2} {3} {4} {5} {6}", - new Object[]{indent, inputIndex, inputContext.getInstrumentedNode().getClass().getSimpleName(), - sourceSectionFormat(context.getInstrumentedSourceSection()), - sourceSectionFormat(inputContext.getInstrumentedSourceSection()), inputValue, - env.findMetaObject(inputContext.getInstrumentedNode().getRootNode().getLanguageInfo(), inputValue)}); - indent.append(" "); - } - }; + public void onInputValue(VirtualFrame frame, EventContext inputContext, int inputIndex, Object inputValue) { + if (LOG.isLoggable(Level.FINEST)) { + logOnInputValue(inputContext, inputIndex, inputValue); + } + CompilerDirectives.transferToInterpreter(); + throw new EvaluationResultException(inputValue); + } + + @TruffleBoundary + private void logOnInputValue(EventContext inputContext, int inputIndex, Object inputValue) { + indent.setLength(indent.length() - 2); + LOG.log(Level.FINEST, "{0}onInputValue idx:{1} {2} {3} {4} {5} {6}", + new Object[]{indent, inputIndex, inputContext.getInstrumentedNode().getClass().getSimpleName(), + sourceSectionFormat(context.getInstrumentedSourceSection()), + sourceSectionFormat(inputContext.getInstrumentedSourceSection()), inputValue, + env.findMetaObject(inputContext.getInstrumentedNode().getRootNode().getLanguageInfo(), inputValue)}); + indent.append(" "); } + }; + } - }); + }); try { callTarget.call(); @@ -458,7 +593,7 @@ public TextDocumentSurrogate createSurrogateForTestFile(TextDocumentSurrogate su runScriptUri = RunScriptUtils.extractScriptPath(surrogateOfOpenedFile); } catch (InvalidCoverageScriptURI e) { throw DiagnosticsNotification.create(surrogateOfOpenedFile.getUri(), - Diagnostic.create(Range.create(0, e.getIndex(), 0, e.getLength()), e.getReason(), DiagnosticSeverity.Error, null, "Graal LSP", null)); + Diagnostic.create(Range.create(0, e.getIndex(), 0, e.getLength()), e.getReason(), DiagnosticSeverity.Error, null, "Graal LSP", null)); } if (runScriptUri == null) { @@ -473,14 +608,6 @@ public TextDocumentSurrogate createSurrogateForTestFile(TextDocumentSurrogate su } - private static String findLanguageOfTestFile(URI runScriptUri, String fallbackLangId) { - try { - return Source.findLanguage(runScriptUri.toURL()); - } catch (IOException e) { - return fallbackLangId; - } - } - private EvaluationResult evalInGlobalScope(String langId, Node nearestNode) { SourceSection section = nearestNode.getSourceSection(); if (section == null || !section.isAvailable()) { @@ -489,63 +616,11 @@ private EvaluationResult evalInGlobalScope(String langId, Node nearestNode) { try { CallTarget callTarget = env.parse( - Source.newBuilder(langId, section.getCharacters(), "eval in global scope").cached(false).build()); + Source.newBuilder(langId, section.getCharacters(), "eval in global scope").cached(false).build()); Object result = callTarget.call(); return EvaluationResult.createResult(result); } catch (Exception e) { return EvaluationResult.createError(e); } } - - /** - * A special method to create a {@link SourceSectionFilter} which filters for a specific source - * section during source code evaluation. We cannot simply filter with - * {@link Builder#sourceIs(Source...)} and {@link Builder#sourceSectionEquals(SourceSection...)} - * , because we are possibly not the creator of the Source and do not know which properties are - * set. The source which is evaluated could have been created by the language. For example by a - * Python import statement. Therefore we need to filter via URI (or name if the URI is a - * generated truffle-schema-URI). - * - * @param uri to filter sources for - * @param sourceSection to filter for with same start and end indices - * @return a builder to add further filter options - */ - static SourceSectionFilter.Builder createSourceSectionFilter(URI uri, SourceSection sourceSection) { - return SourceSectionFilter.newBuilder() // - .lineStartsIn(IndexRange.between(sourceSection.getStartLine(), sourceSection.getStartLine() + 1)) // - .lineEndsIn(IndexRange.between(sourceSection.getEndLine(), sourceSection.getEndLine() + 1)) // - .columnStartsIn(IndexRange.between(sourceSection.getStartColumn(), sourceSection.getStartColumn() + 1)) // - .columnEndsIn(IndexRange.between(sourceSection.getEndColumn(), sourceSection.getEndColumn() + 1)) // - .sourceIs(SourcePredicateBuilder.newBuilder().uriOrTruffleName(uri).build()); - } - - static List findCoverageDataBeforeNode(TextDocumentSurrogate surrogate, Node targetNode) { - List coveragesBeforeNode = new ArrayList<>(); - targetNode.getRootNode().accept(new NodeVisitor() { - boolean found = false; - - @Override - public boolean visit(Node node) { - if (found) { - return false; - } - - if (node.equals(targetNode)) { - found = true; - return false; - } - - SourceSection sourceSection = node.getSourceSection(); - if (sourceSection != null && sourceSection.isAvailable()) { - List coverageData = surrogate.getCoverageData(sourceSection); - if (coverageData != null) { - coveragesBeforeNode.addAll(coverageData); - } - } - - return true; - } - }); - return coveragesBeforeNode; - } } From fea8255e7520d1d9e7d27a12078b877c2491834d Mon Sep 17 00:00:00 2001 From: bakoe Date: Thu, 30 Jan 2020 11:25:13 +0100 Subject: [PATCH 2/3] Apply IntellIJ formatting to LanguageServerImpl --- .../tools/lsp/server/LanguageServerImpl.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java index 002f8f58c8e9..87e65b957428 100644 --- a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java +++ b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java @@ -150,7 +150,7 @@ public void connect(@SuppressWarnings("hiding") LanguageClient client) { @Override public CompletableFuture completion(CompletionParams position) { Future futureCompletionList = truffleAdapter.completion(URI.create(position.getTextDocument().getUri()), position.getPosition().getLine(), - position.getPosition().getCharacter(), position.getContext()); + position.getPosition().getCharacter(), position.getContext()); return CompletableFuture.supplyAsync(() -> waitForResultAndHandleExceptions(futureCompletionList, truffleAdapter.completionHandler.emptyList)); } @@ -185,7 +185,7 @@ public CompletableFuture> references(ReferenceParams pa @Override public CompletableFuture> documentHighlight(TextDocumentPositionParams position) { Future> future = truffleAdapter.documentHighlight(URI.create(position.getTextDocument().getUri()), position.getPosition().getLine(), - position.getPosition().getCharacter()); + position.getPosition().getCharacter()); Supplier> supplier = () -> waitForResultAndHandleExceptions(future, Collections.emptyList()); return CompletableFuture.supplyAsync(supplier); } @@ -280,7 +280,7 @@ public void didChange(DidChangeTextDocumentParams params) { } private void processChanges(final String documentUri, - final List list) { + final List list) { String langId = openedFileUri2LangId.get(URI.create(documentUri)); if (langId == null) { LOG.warning("Changed document that was not opened: " + documentUri); @@ -351,25 +351,25 @@ private void extractAndEvaluateExamples(URI uri, String sourceCode) { .map(CompletableFuture::join) .flatMap(example -> { ArrayList decorations = new ArrayList<>(); - for (ProbeDefinition probe : example.getProbes()) { - decorations.add(Decoration.create( - Range.create( - Position.create(probe.getLine(), probe.getStartColumn()), - Position.create(probe.getLine(), probe.getEndColumn()) - ), - probe.getResult().toString(), - "probeResult" - )); - } + for (ProbeDefinition probe : example.getProbes()) { decorations.add(Decoration.create( Range.create( - Position.create(example.getExampleDefinitionLine(), 0), - Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) + Position.create(probe.getLine(), probe.getStartColumn()), + Position.create(probe.getLine(), probe.getEndColumn()) ), - example.getExampleResult().toString(), - "exampleResult" + probe.getResult().toString(), + "probeResult" )); - return decorations.stream(); + } + decorations.add(Decoration.create( + Range.create( + Position.create(example.getExampleDefinitionLine(), 0), + Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) + ), + example.getExampleResult().toString(), + "exampleResult" + )); + return decorations.stream(); }).collect(Collectors.toList()) ) .thenAccept(decorations -> client.publishDecorations(PublishDecorationsParams.create(uri.toString(), decorations))); From 94da06b01892234a41b83826d63dffd6db1ccb1a Mon Sep 17 00:00:00 2001 From: bakoe Date: Thu, 30 Jan 2020 11:30:41 +0100 Subject: [PATCH 3/3] Factor out getListOfDecorationsForEvaluatedExample --- .../tools/lsp/server/LanguageServerImpl.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java index 87e65b957428..a8dc3a6f2319 100644 --- a/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java +++ b/tools/src/org.graalvm.tools.lsp/src/org/graalvm/tools/lsp/server/LanguageServerImpl.java @@ -333,6 +333,29 @@ public CompletableFuture> symbol(WorkspaceSymb return CompletableFuture.completedFuture(Collections.emptyList()); } + private List getListOfDecorationsForEvaluatedExample(ExampleDefinition example) { + ArrayList decorations = new ArrayList<>(); + for (ProbeDefinition probe : example.getProbes()) { + decorations.add(Decoration.create( + Range.create( + Position.create(probe.getLine(), probe.getStartColumn()), + Position.create(probe.getLine(), probe.getEndColumn()) + ), + probe.getResult().toString(), + "probeResult" + )); + } + decorations.add(Decoration.create( + Range.create( + Position.create(example.getExampleDefinitionLine(), 0), + Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) + ), + example.getExampleResult().toString(), + "exampleResult" + )); + return decorations; + } + private void extractAndEvaluateExamples(URI uri, String sourceCode) { Future> exampleDefinitionsFuture = truffleAdapter.exampleDefinitions(uri, sourceCode); Supplier> supplier = () -> waitForResultAndHandleExceptions(exampleDefinitionsFuture, new ArrayList<>()); @@ -349,28 +372,7 @@ private void extractAndEvaluateExamples(URI uri, String sourceCode) { CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) .thenApply(ignored -> futures.stream() .map(CompletableFuture::join) - .flatMap(example -> { - ArrayList decorations = new ArrayList<>(); - for (ProbeDefinition probe : example.getProbes()) { - decorations.add(Decoration.create( - Range.create( - Position.create(probe.getLine(), probe.getStartColumn()), - Position.create(probe.getLine(), probe.getEndColumn()) - ), - probe.getResult().toString(), - "probeResult" - )); - } - decorations.add(Decoration.create( - Range.create( - Position.create(example.getExampleDefinitionLine(), 0), - Position.create(example.getExampleDefinitionLine(), example.getExampleDefinitionEndColumn()) - ), - example.getExampleResult().toString(), - "exampleResult" - )); - return decorations.stream(); - }).collect(Collectors.toList()) + .flatMap(example -> getListOfDecorationsForEvaluatedExample(example).stream()).collect(Collectors.toList()) ) .thenAccept(decorations -> client.publishDecorations(PublishDecorationsParams.create(uri.toString(), decorations))); }