/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* 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 lpg.lpgjavaruntime.IToken;
import lpg.lpgjavaruntime.PrsStream;
import lpg.lpgjavaruntime.Token;
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;
/**
* 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<String,String>();
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(tu!=null){
tu.setIsHeaderUnit((options & OPTION_IS_SOURCE_UNIT) == 0); // the TU is marked as either a source file or a header file
}
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<String,String>();
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());
@SuppressWarnings("unchecked")
@Override
public Object getAdapter(Class adapter) {
if(ICLanguageKeywords.class.equals(adapter))
return cLanguageKeywords;
if(IPDOMLinkageFactory.class.equals(adapter)) {
if(getParserLanguage().isCPP())
return new PDOMCPPLinkageFactory();
return new PDOMCLinkageFactory();
}
return super.getAdapter(adapter);
}
@Override
public IContributedModelBuilder createModelBuilder(@SuppressWarnings("unused") ITranslationUnit tu) {
return null;
}
}