Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -30,6 +30,7 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
Expand Down Expand Up @@ -62,6 +63,7 @@ public class TextDocumentState {

private final BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parser;
private final ISourceLocation location;
private final ExecutorService exec;

private final AtomicReference<Versioned<Update>> current;
private final AtomicReference<@Nullable Versioned<ITree>> lastWithoutErrors;
Expand All @@ -70,15 +72,17 @@ public class TextDocumentState {
public TextDocumentState(
BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parser,
ISourceLocation location,
int initialVersion, String initialContent, long initialTimestamp) {
int initialVersion, String initialContent, long initialTimestamp,
ExecutorService exec) {

this.parser = parser;
this.location = location;
this.lastWithoutErrors = new AtomicReference<>();
this.last = new AtomicReference<>();
Comment thread
sungshik marked this conversation as resolved.
this.exec = exec;

var u = new Update(initialVersion, initialContent, initialTimestamp);
this.current = new AtomicReference<>(new Versioned<>(initialVersion, u));
this.lastWithoutErrors = new AtomicReference<>();
this.last = new AtomicReference<>();
}

public ISourceLocation getLocation() {
Expand Down Expand Up @@ -200,28 +204,35 @@ public CompletableFuture<Versioned<List<Diagnostics.Template>>> getDiagnosticsAs
private void parse() {
try {
parser.apply(location, content)
.whenComplete((ITree t, Throwable e) -> {
if (e instanceof CompletionException && e.getCause() != null) {
e = e.getCause();
}
var diagnosticsList = toDiagnosticsList(t, e); // `t` and `e` are nullable

// Complete future to get the tree
if (t == null) {
treeAsync.completeExceptionally(e);
} else {
var tree = new Versioned<>(version, t, timestamp);
Versioned.replaceIfNewer(last, tree);
if (diagnosticsList.isEmpty()) {
Versioned.replaceIfNewer(lastWithoutErrors, tree);
.whenCompleteAsync((ITree t, Throwable e) -> {
try {
if (e instanceof CompletionException && e.getCause() != null) {
e = e.getCause();
}
var diagnosticsList = toDiagnosticsList(t, e); // `t` and `e` are nullable

// Complete future to get the tree
if (t == null) {
treeAsync.completeExceptionally(e);
} else {
var tree = new Versioned<>(version, t, timestamp);
Versioned.replaceIfNewer(last, tree);
if (diagnosticsList.isEmpty()) {
Versioned.replaceIfNewer(lastWithoutErrors, tree);
}
treeAsync.complete(tree);
}
treeAsync.complete(tree);
}

// Complete future to get diagnostics
var diagnostics = new Versioned<>(version, diagnosticsList);
diagnosticsAsync.complete(diagnostics);
});
// Complete future to get diagnostics
var diagnostics = new Versioned<>(version, diagnosticsList);
diagnosticsAsync.complete(diagnostics);
} catch (Exception exc) {
Comment thread
sungshik marked this conversation as resolved.
// The action of `whenCompleteAsync` shouldn't throw an exception (see JavaDoc): if it
// unexpectedly does, then it is almost surely a bug, but the exception is swallowed, so it
// is very hard to debug. The try/catch block and logger call aim to make it easier.
logger.error("Unexpected exception after parsing", exc);
}
}, exec);
} catch (NoContributionException e) {
logger.debug("Ignoring missing parser for {}", location, e);
treeAsync.completeOnTimeout(new Versioned<>(version, IRascalValueFactory.getInstance().character(0), timestamp), 60, TimeUnit.SECONDS);
Expand Down Expand Up @@ -255,6 +266,6 @@ public long getLastModified() {

public TextDocumentState changeParser(BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parsing) {
var c = getCurrentContent();
return new TextDocumentState(parsing, this.location, c.version(), c.get(), getLastModified());
return new TextDocumentState(parsing, this.location, c.version(), c.get(), getLastModified(), exec);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ private ParametricFileFacts facts(ISourceLocation doc) {

private TextDocumentState open(TextDocumentItem doc, long timestamp) {
return files.computeIfAbsent(Locations.toLoc(doc),
l -> new TextDocumentState(contributions(l)::parsing, l, doc.getVersion(), doc.getText(), timestamp));
l -> new TextDocumentState(contributions(l)::parsing, l, doc.getVersion(), doc.getText(), timestamp, exec));
}

private TextDocumentState getFile(ISourceLocation loc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ private static <T> T last(List<T> l) {

private TextDocumentState open(TextDocumentItem doc, long timestamp) {
return documents.computeIfAbsent(Locations.toLoc(doc),
l -> new TextDocumentState(availableRascalServices()::parseSourceFile, l, doc.getVersion(), doc.getText(), timestamp));
l -> new TextDocumentState(availableRascalServices()::parseSourceFile, l, doc.getVersion(), doc.getText(), timestamp, exec));
}

private TextDocumentState getFile(TextDocumentIdentifier doc) {
Expand Down
Loading