/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.tvl.goworks.editor.go.parser;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.netbeans.editor.classification.TokenTag;
import org.antlr.netbeans.editor.tagging.Tagger;
import org.antlr.netbeans.editor.text.DocumentSnapshot;
import org.antlr.netbeans.parsing.spi.BaseParserData;
import org.antlr.netbeans.parsing.spi.ParseContext;
import org.antlr.netbeans.parsing.spi.ParserData;
import org.antlr.netbeans.parsing.spi.ParserDataDefinition;
import org.antlr.netbeans.parsing.spi.ParserResultHandler;
import org.antlr.netbeans.parsing.spi.ParserTaskManager;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.works.editor.antlr4.classification.TaggerTokenSource;
import org.antlr.works.editor.antlr4.parsing.SyntaxErrorListener;
import org.netbeans.api.annotations.common.NonNull;
import org.openide.filesystems.FileObject;
import org.openide.util.Parameters;
import org.tvl.goworks.editor.go.GoParserDataDefinitions;
import org.tvl.goworks.editor.go.parser.generated.AbstractGoParser.SourceFileContext;
/**
*
* @author Sam Harwell
*/
public class CompiledModelParser {
// -J-Dorg.tvl.goworks.editor.go.parser.CompiledModelParser.level=FINE
private static final Logger LOGGER = Logger.getLogger(CompiledModelParser.class.getName());
private final Object lock = new Object();
private DocumentSnapshot lastSnapshot;
private CompiledFileModel lastResult;
private Throwable lastException;
public void parse(ParserTaskManager taskManager, ParseContext context, DocumentSnapshot snapshot, Collection<? extends ParserDataDefinition<?>> requestedData, ParserResultHandler results)
throws InterruptedException, ExecutionException {
try {
if (requestedData.contains(GoParserDataDefinitions.COMPILED_MODEL)) {
CompiledModel result = parseImpl(taskManager, context, snapshot);
BaseParserData<CompiledModel> data = new BaseParserData<>(context, GoParserDataDefinitions.COMPILED_MODEL, snapshot, result);
results.addResult(data);
}
} catch (ExecutionException ex) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "An error occurred while parsing.", ex);
}
}
}
protected CompiledModel parseImpl(@NonNull ParserTaskManager taskManager, ParseContext context, DocumentSnapshot snapshot)
throws InterruptedException, ExecutionException {
Parameters.notNull("snapshot", snapshot);
synchronized (lock) {
if (snapshot.equals(lastSnapshot)) {
if (lastException != null) {
throw new ExecutionException("An unexpected error occurred.", lastException);
}
return new CompiledModel(snapshot, lastResult);
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Reparsing snapshot {0}", snapshot);
}
try {
Future<ParserData<Tagger<TokenTag<Token>>>> futureTokensData = taskManager.getData(snapshot, GoParserDataDefinitions.LEXER_TOKENS);
Tagger<TokenTag<Token>> tagger = futureTokensData != null ? futureTokensData.get().getData() : null;
TaggerTokenSource tokenSource = new TaggerTokenSource(tagger, snapshot);
CommonTokenStream tokenStream = new CommonTokenStream(tokenSource);
GoParser parser = GoParserFactory.DEFAULT.getParser(tokenStream, ParserConfiguration.FASTEST);
try {
SyntaxErrorListener syntaxErrorListener = new SyntaxErrorListener(snapshot);
SourceFileContext sourceFileContext;
try {
try {
sourceFileContext = parser.sourceFile();
} catch (ParseCancellationException ex) {
if (ex.getCause() instanceof RecognitionException) {
// retry with hybrid parser
tokenStream.reset();
parser = GoParserFactory.DEFAULT.getParser(tokenStream, ParserConfiguration.HYBRID);
sourceFileContext = parser.sourceFile();
} else {
throw ex;
}
}
} catch (ParseCancellationException ex) {
if (ex.getCause() instanceof RecognitionException) {
// retry with precise parser and default error handler
tokenStream.reset();
parser = GoParserFactory.DEFAULT.getParser(tokenStream, ParserConfiguration.PRECISE);
parser.removeErrorListeners();
parser.addErrorListener(syntaxErrorListener);
sourceFileContext = parser.sourceFile();
} else {
throw ex;
}
}
FileObject fileObject = snapshot.getVersionedDocument().getFileObject();
Token[] groupTokens = tokenStream.getTokens().toArray(new Token[0]);
lastSnapshot = snapshot;
lastResult = new CompiledFileModel(sourceFileContext, syntaxErrorListener.getSyntaxErrors(), fileObject, groupTokens);
lastException = null;
return new CompiledModel(snapshot, lastResult);
} catch (RecognitionException ex) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "A recognition exception occurred while parsing.", ex);
}
lastSnapshot = snapshot;
lastResult = null;
lastException = null;
return null;
}
} catch (InterruptedException | ExecutionException | ParseCancellationException ex) {
lastSnapshot = snapshot;
lastResult = null;
lastException = ex;
throw new ExecutionException("An unexpected error occurred.", ex);
}
}
}
}