blob: 0d8f81a03497bcd460bdff17b52f314d6bf9f216 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.lrparser;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.gnu.c.GCCLanguage;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage;
import org.eclipse.cdt.core.dom.lrparser.action.ITokenStream;
import org.eclipse.cdt.core.dom.parser.CLanguageKeywords;
import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.AbstractLanguage;
import org.eclipse.cdt.core.model.ICLanguageKeywords;
import org.eclipse.cdt.core.model.IContributedModelBuilder;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.FileContent;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.ASTPrinter;
import org.eclipse.cdt.core.parser.util.DebugUtil;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.c.PDOMCLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.cpp.PDOMCPPLinkageFactory;
import org.eclipse.core.runtime.CoreException;
import lpg.lpgjavaruntime.IToken;
import lpg.lpgjavaruntime.PrsStream;
/**
* Implementation of the ILanguage extension point,
* provides the ability to add LPG based languages to CDT.
*/
@SuppressWarnings({ "restriction", "nls" })
public abstract class BaseExtensibleLanguage extends AbstractLanguage {
private static final boolean DEBUG_PRINT_GCC_AST = false;
private static final boolean DEBUG_PRINT_AST = false;
// default 0.5 min
private long parser_timeout_limit_lowerBoundary = 1 * 30 * 1000;
// default 2 mins
private long parser_timeout_limit_uppperBoundary = 1 * 60 * 1000;
//time limit for each token, 1ms
public static long UNIT_PARSER_TIMEOUT_LIMIT = 10;
private static long LONGEST_CORE_RUNTIME;
private static long LONGEST_LPR_RUNTIME;
public static boolean CATCH_TEMPLATEID_ERROR = false;
private ICLanguageKeywords keywords = null;
/**
* Retrieve the parser (runs after the preprocessor runs).
*
* Can be overridden in subclasses to provide a different parser
* for a language extension.
*/
protected abstract IParser<IASTTranslationUnit> getParser(IScanner scanner, IIndex index,
Map<String, String> properties);
protected IParser<IASTTranslationUnit> getCompleteParser(IScanner scanner, IIndex index,
Map<String, String> properties) {
return getParser(scanner, index, properties);
}
protected ISecondaryParser<IASTTranslationUnit> getCompleteParser(ITokenStream stream, IScanner scanner,
IIndex index, Map<String, String> properties) {
return (ISecondaryParser) getParser(scanner, index, properties);
}
/**
* Returns the ParserLanguage value that is to be used when creating
* an instance of CPreprocessor.
*
*/
protected abstract ParserLanguage getParserLanguage();
/**
* Returns the scanner extension configuration for this language, may not return null
*/
protected abstract IScannerExtensionConfiguration getScannerExtensionConfiguration();
private class ParseThread<AST_TYPE> extends Thread {
ParseThread() {
super();
super.setName("ParserThread");
}
AST_TYPE astUnit = null;
AST_TYPE getASTUnit() {
return astUnit;
}
}
private <AST_TYPE> AST_TYPE runThreadByLimitedTime(long limitTime, ParseThread<AST_TYPE> parseThread)
throws InterruptedException {
parseThread.start();
parseThread.join(limitTime);
return parseThread.getASTUnit();
}
@Override
@Deprecated
public IASTTranslationUnit getASTTranslationUnit(org.eclipse.cdt.core.parser.CodeReader reader,
IScannerInfo scanInfo, ICodeReaderFactory codeReaderFactory, IIndex index, int options,
IParserLogService log) throws CoreException {
return getASTTranslationUnit(FileContent.adapt(reader), scanInfo,
IncludeFileContentProvider.adapt(codeReaderFactory), index, options, log);
}
public void setParser_timeout_limit_lowerBoundary(long parser_timeout_limit_lowerBoundary) {
this.parser_timeout_limit_lowerBoundary = parser_timeout_limit_lowerBoundary;
}
public void setParser_timeout_limit_uppperBoundary(long parser_timeout_limit_uppperBoundary) {
this.parser_timeout_limit_uppperBoundary = parser_timeout_limit_uppperBoundary;
}
@Override
public IASTTranslationUnit getASTTranslationUnit(final FileContent reader, final IScannerInfo scanInfo,
final IncludeFileContentProvider fileCreator, final IIndex index, int options, final IParserLogService log)
throws CoreException {
CATCH_TEMPLATEID_ERROR = false;
long startTime = 0;
java.util.Date today = null;
if (log.isTracing()) {
today = new java.util.Date();
startTime = today.getTime();
log.traceLog(
"^^^^^^ Start parsing " + reader.getFileLocation() + " at " + new java.sql.Timestamp(startTime));
}
IASTTranslationUnit gtu = null;
if (DEBUG_PRINT_GCC_AST) {
System.out.println(
"\n********************************************************\nParsing\nOptions: " + options);
ILanguage gppLanguage = getParserLanguage() == ParserLanguage.CPP ? GPPLanguage.getDefault()
: GCCLanguage.getDefault();
gtu = gppLanguage.getASTTranslationUnit(reader, scanInfo, fileCreator, index, options, log);
System.out.println(gppLanguage.getName() + " AST:");
ASTPrinter.print(gtu);
System.out.println();
}
final IScannerExtensionConfiguration config = getScannerExtensionConfiguration();
final ParserLanguage pl = getParserLanguage();
final IScanner preprocessor = new CPreprocessor(reader, scanInfo, pl, log, config, fileCreator);
preprocessor.setComputeImageLocations((options & ILanguage.OPTION_NO_IMAGE_LOCATIONS) == 0);
final Map<String, String> parserProperties = new HashMap<>();
parserProperties.put(LRParserProperties.TRANSLATION_UNIT_PATH, reader.getFileLocation());
if ((options & OPTION_SKIP_FUNCTION_BODIES) != 0)
parserProperties.put(LRParserProperties.SKIP_FUNCTION_BODIES, "true");
if ((options & OPTION_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS) != 0)
parserProperties.put(LRParserProperties.SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS, "true");
final IParser<IASTTranslationUnit> parser = getParser(preprocessor, index, parserProperties);
long parser_timeout_limit = parser_timeout_limit_uppperBoundary;
if (parser instanceof PrsStream) {
int token_size = ((PrsStream) parser).getSize();
parser_timeout_limit = token_size * UNIT_PARSER_TIMEOUT_LIMIT;
if (parser_timeout_limit < parser_timeout_limit_lowerBoundary)
parser_timeout_limit = parser_timeout_limit_lowerBoundary;
if (parser_timeout_limit > parser_timeout_limit_uppperBoundary)
parser_timeout_limit = parser_timeout_limit_uppperBoundary;
log.traceLog("^^^^^^ adjusted time out limit with token size: " + token_size + " and the time out limit: "
+ parser_timeout_limit);
}
IASTTranslationUnit tu = null;
//real token size, substract a dummy token and a eof token
final int orgTokenSize = ((PrsStream) parser).getTokens().size();
//final List orginalTokens = copyList(((PrsStream)parser).getTokens());
ParseThread<IASTTranslationUnit> parseThread = new ParseThread<IASTTranslationUnit>() {
@Override
public void run() {
try {
astUnit = parser.parse();
}
catch (Exception e) {
/*
if(e instanceof TemplateIDErrorException){
//IScanner completePreprocessor = new CPreprocessor(reader, scanInfo, pl, log, config, fileCreator);
//IParser<IASTTranslationUnit> completeParser = getCompleteParser(preprocessor, index, parserProperties);
ISecondaryParser<IASTTranslationUnit> completeParser = getCompleteParser((ITokenStream)parser, preprocessor, index, parserProperties);
//completeParser.setAction(parser.getAction());
//((ISecondaryParser)completeParser).setTokenMap((ITokenStream)parser);
//copyTokensToParser((PrsStream)completeParser, ((PrsStream)parser).getTokens().subList(0, orgTokenSize));
((ISecondaryParser)completeParser).setTokens(((PrsStream)parser).getTokens().subList(1, orgTokenSize-1));
astUnit = completeParser.parse();
}else{
*/
if (log.isTracing()) {
StringWriter stringW = new StringWriter();
PrintWriter printW = new PrintWriter(stringW);
e.printStackTrace(printW);
log.traceLog("^^^^^^ PARSER_ERR_STACK" + stringW.toString());
}
//}
}
}
};
try {
tu = runThreadByLimitedTime(parser_timeout_limit, parseThread);
} catch (InterruptedException e) {
StringWriter stringW = new StringWriter();
PrintWriter printW = new PrintWriter(stringW);
e.printStackTrace(printW);
log.traceLog("^^^^^^_ERR_STACK" + stringW.toString());
//e.printStackTrace();
}
parseThread.stop();
long lprFinishTime = 0;
long coreFinishTime = 0;
if (log.isTracing()) {
today = new java.util.Date();
lprFinishTime = today.getTime();
}
if (tu == null) {
long lpr_fail_time = 0;
if (log.isTracing()) {
lpr_fail_time = lprFinishTime;
log.traceLog("^^^^^^ LR parser fails in parsing " + reader.getFileLocation() + " after running "
+ (lpr_fail_time - startTime) / 1000 + " seconds");
}
ILanguage gppLanguage = getParserLanguage() == ParserLanguage.CPP ? GPPLanguage.getDefault()
: GCCLanguage.getDefault();
tu = gppLanguage.getASTTranslationUnit(reader, scanInfo, fileCreator, index, options, log);
if (log.isTracing()) {
today = new java.util.Date();
coreFinishTime = today.getTime();
log.traceLog("^^^^^^ core parser parses " + reader.getFileLocation() + " in "
+ (coreFinishTime - lpr_fail_time) / 1000 + " seconds");
}
}
if (DEBUG_PRINT_AST) {
System.out.println("Base Extensible Language AST:");
ASTPrinter.print(tu);
}
long finishTime;
if (log.isTracing()) {
if (coreFinishTime > 0) {
//parsed by core parser.
finishTime = coreFinishTime;
long core_runtime = finishTime - startTime;
log.traceLog("^^^^^^ Finish parsing with cdt core parser " + reader.getFileLocation() + " at "
+ new java.sql.Timestamp(finishTime) + " runtime: " + core_runtime);
if (core_runtime > LONGEST_CORE_RUNTIME) {
LONGEST_CORE_RUNTIME = core_runtime;
log.traceLog(
"^^^^^^ CLCLCLCL so far the longest runtime with core parser is: " + core_runtime / 1000);
}
} else {
finishTime = lprFinishTime;
long lpr_runtime = finishTime - startTime;
log.traceLog("^^^^^^ Finish parsing " + reader.getFileLocation() + " at "
+ new java.sql.Timestamp(finishTime) + " runtime: " + lpr_runtime);
if (lpr_runtime > LONGEST_LPR_RUNTIME) {
LONGEST_LPR_RUNTIME = lpr_runtime;
log.traceLog("^^^^^^ LLLLLLLL so far the longest runtime by LPR Parser is: " + lpr_runtime / 1000);
}
}
}
return tu;
}
public void copyTokensToParser(PrsStream parser, List<IToken> tokens) {
parser.resetTokenStream();
for (IToken token : tokens) {
parser.addToken(token);
}
}
public List copyList(List orgList) {
List returnList = new ArrayList(orgList.size());
for (int i = 0; i < orgList.size(); i++) {
returnList.add(orgList.get(i));
}
return returnList;
}
@Override
@Deprecated
public IASTTranslationUnit getASTTranslationUnit(org.eclipse.cdt.core.parser.CodeReader reader,
IScannerInfo scanInfo, ICodeReaderFactory fileCreator, IIndex index, IParserLogService log)
throws CoreException {
return getASTTranslationUnit(reader, scanInfo, fileCreator, index, 0, log);
}
@Override
@Deprecated
public IASTCompletionNode getCompletionNode(org.eclipse.cdt.core.parser.CodeReader reader, IScannerInfo scanInfo,
ICodeReaderFactory fileCreator, IIndex index, IParserLogService log, int offset) throws CoreException {
return getCompletionNode(FileContent.adapt(reader), scanInfo, IncludeFileContentProvider.adapt(fileCreator),
index, log, offset);
}
@Override
public IASTCompletionNode getCompletionNode(FileContent reader, IScannerInfo scanInfo,
IncludeFileContentProvider fileCreator, IIndex index, IParserLogService log, int offset)
throws CoreException {
IASTCompletionNode cn;
if (DEBUG_PRINT_GCC_AST) {
ILanguage gppLanguage = GCCLanguage.getDefault();
cn = gppLanguage.getCompletionNode(reader, scanInfo, fileCreator, index, log, offset);
System.out.println();
System.out.println("********************************************************");
System.out.println("GPP AST:");
printCompletionNode(cn);
}
IScannerExtensionConfiguration config = getScannerExtensionConfiguration();
ParserLanguage pl = getParserLanguage();
IScanner preprocessor = new CPreprocessor(reader, scanInfo, pl, log, config, fileCreator);
preprocessor.setContentAssistMode(offset);
Map<String, String> parserProperties = new HashMap<>();
parserProperties.put(LRParserProperties.TRANSLATION_UNIT_PATH, reader.getFileLocation());
parserProperties.put(LRParserProperties.SKIP_FUNCTION_BODIES, "true");
parserProperties.put(LRParserProperties.SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS, "true");
final IParser<IASTTranslationUnit> parser = getParser(preprocessor, index, parserProperties);
long parser_timeout_limit = parser_timeout_limit_uppperBoundary;
if (parser instanceof PrsStream) {
int token_size = ((PrsStream) parser).getSize();
parser_timeout_limit = token_size * UNIT_PARSER_TIMEOUT_LIMIT;
if (parser_timeout_limit < parser_timeout_limit_lowerBoundary)
parser_timeout_limit = parser_timeout_limit_lowerBoundary;
if (parser_timeout_limit > parser_timeout_limit_uppperBoundary)
parser_timeout_limit = parser_timeout_limit_uppperBoundary;
if (log.isTracing()) {
log.traceLog("^^^^^^ adjusted time out limit with token size: " + token_size
+ " and the time out limit: " + parser_timeout_limit);
}
}
ParseThread<IASTCompletionNode> parseThread = new ParseThread<IASTCompletionNode>() {
@Override
public void run() {
parser.parse();
astUnit = parser.getCompletionNode();
}
};
IASTCompletionNode completionNode = null;
try {
completionNode = runThreadByLimitedTime(parser_timeout_limit * 100, parseThread);
} catch (InterruptedException e) {
if (log.isTracing()) {
StringWriter stringW = new StringWriter();
PrintWriter printW = new PrintWriter(stringW);
e.printStackTrace(printW);
log.traceLog("^^^^^^_ERR_STACK" + stringW.toString());
}
//e.printStackTrace();
}
parseThread.stop();
if (completionNode == null) {
log.traceLog("LR parser fails in parsing " + reader.getFileLocation());
if (log.isTracing()) {
log.traceLog("LR parser fails in parsing " + reader.getFileLocation());
}
ILanguage gppLanguage = getParserLanguage() == ParserLanguage.CPP ? GPPLanguage.getDefault()
: GCCLanguage.getDefault();
completionNode = gppLanguage.getCompletionNode(reader, scanInfo, fileCreator, index, log, offset);
}
if (DEBUG_PRINT_AST) {
System.out.println("Base Extensible Language AST:");
printCompletionNode(completionNode);
}
return completionNode;
}
/*
* For debugging.
*/
private static void printCompletionNode(IASTCompletionNode cn) {
if (cn == null) {
System.out.println("Completion node is null");
return;
}
ASTPrinter.print(cn.getTranslationUnit());
for (IASTName name : cn.getNames()) {
ASTNode context = (ASTNode) name.getCompletionContext();
System.out.printf("Name: %s, Context: %s, At: %d", name, DebugUtil.safeClassName(context),
context == null ? null : context.getOffset());
if (name.getTranslationUnit() == null) // some name nodes are not hooked up to the AST
System.out.print(", not hooked up");
System.out.println();
}
System.out.println();
}
@Override
@Deprecated
public IASTName[] getSelectedNames(IASTTranslationUnit ast, int start, int length) {
return GCCLanguage.getDefault().getSelectedNames(ast, start, length);
}
private ICLanguageKeywords cLanguageKeywords = new CLanguageKeywords(getParserLanguage(),
getScannerExtensionConfiguration());
@Override
public <T> T getAdapter(Class<T> adapter) {
if (ICLanguageKeywords.class.equals(adapter))
return adapter.cast(cLanguageKeywords);
if (IPDOMLinkageFactory.class.equals(adapter)) {
if (getParserLanguage().isCPP())
return adapter.cast(new PDOMCPPLinkageFactory());
return adapter.cast(new PDOMCLinkageFactory());
}
return super.getAdapter(adapter);
}
@Override
public IContributedModelBuilder createModelBuilder(@SuppressWarnings("unused") ITranslationUnit tu) {
return null;
}
}