/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.lang.parser;
import com.google.common.base.Strings;
import com.google.common.collect.Ordering;
import com.intellij.lang.ASTFactory;
import com.intellij.lang.ASTNode;
import com.intellij.psi.impl.source.javadoc.PsiDocCommentImpl;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.LazyParseableElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.util.containers.SortedList;
import gw.lang.parser.IDynamicFunctionSymbol;
import gw.lang.parser.IExpression;
import gw.lang.parser.IParseTree;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.IProgramClassFunctionSymbol;
import gw.lang.parser.ISourceCodeTokenizer;
import gw.lang.parser.IStatement;
import gw.lang.parser.IToken;
import gw.lang.parser.Keyword;
import gw.lang.parser.expressions.*;
import gw.lang.parser.statements.IArrayAssignmentStatement;
import gw.lang.parser.statements.IAssignmentStatement;
import gw.lang.parser.statements.IBeanMethodCallStatement;
import gw.lang.parser.statements.IBlockInvocationStatement;
import gw.lang.parser.statements.IBreakStatement;
import gw.lang.parser.statements.ICaseClause;
import gw.lang.parser.statements.ICatchClause;
import gw.lang.parser.statements.IClassDeclaration;
import gw.lang.parser.statements.IClassFileStatement;
import gw.lang.parser.statements.IClassStatement;
import gw.lang.parser.statements.IClasspathStatement;
import gw.lang.parser.statements.IConstructorStatement;
import gw.lang.parser.statements.IContinueStatement;
import gw.lang.parser.statements.IDoWhileStatement;
import gw.lang.parser.statements.IEvalStatement;
import gw.lang.parser.statements.IForEachStatement;
import gw.lang.parser.statements.IFunctionStatement;
import gw.lang.parser.statements.IHideFieldNoOpStatement;
import gw.lang.parser.statements.IIfStatement;
import gw.lang.parser.statements.IInterfacesClause;
import gw.lang.parser.statements.IMapAssignmentStatement;
import gw.lang.parser.statements.IMemberAssignmentStatement;
import gw.lang.parser.statements.IMethodCallStatement;
import gw.lang.parser.statements.INamespaceStatement;
import gw.lang.parser.statements.INewStatement;
import gw.lang.parser.statements.INoOpStatement;
import gw.lang.parser.statements.INotAStatement;
import gw.lang.parser.statements.IPropertyStatement;
import gw.lang.parser.statements.IReturnStatement;
import gw.lang.parser.statements.IStatementList;
import gw.lang.parser.statements.ISuperTypeClause;
import gw.lang.parser.statements.ISwitchStatement;
import gw.lang.parser.statements.ISyntheticFunctionStatement;
import gw.lang.parser.statements.ISyntheticMemberAccessStatement;
import gw.lang.parser.statements.IThrowStatement;
import gw.lang.parser.statements.ITryCatchFinallyStatement;
import gw.lang.parser.statements.ITypeVariableExtendsListClause;
import gw.lang.parser.statements.IUsesStatement;
import gw.lang.parser.statements.IUsesStatementList;
import gw.lang.parser.statements.IUsingStatement;
import gw.lang.parser.statements.IWhileStatement;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.gs.IGosuEnhancement;
import gw.lang.reflect.gs.IGosuProgram;
import gw.lang.reflect.java.JavaTypes;
import gw.plugin.ij.lang.GosuCommentImpl;
import gw.plugin.ij.lang.GosuTokenImpl;
import gw.plugin.ij.lang.GosuTokenTypes;
import gw.plugin.ij.lang.IGosuElementType;
import gw.plugin.ij.lang.psi.impl.expressions.GosuIdentifierImpl;
import gw.plugin.ij.lang.psi.impl.expressions.LightGosuIdentifierImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Comparator;
import java.util.List;
public class GosuAstTransformer {
private static final GosuAstTransformer INSTANCE = new GosuAstTransformer();
@NotNull
public static GosuAstTransformer instance() {
return INSTANCE;
}
@NotNull
public ASTNode transformClass(@NotNull ASTNode chameleon, @NotNull IGosuClass gosuClass) {
LazyParseableElement rootFileNode = ASTFactory.lazy((IFileElementType) chameleon.getElementType(), null);
gosuClass.isValid();
IClassFileStatement cfs = gosuClass.getClassStatement().getClassFileStatement();
// ParseTreeUtil.dumpParseTree(cfs, "");
makeAstTree(rootFileNode, cfs);
return rootFileNode;
}
@NotNull
public ASTNode transformProgram(@NotNull ASTNode chameleon, @NotNull IGosuProgram gosuProgram) {
LazyParseableElement rootFileNode = ASTFactory.lazy((IFileElementType) chameleon.getElementType(), null);
gosuProgram.isValid();
// Wrap the program in a nice warm Gosu class. This effectively makes program files appear as toplevel psi classes
CompositeElement classStmtNode = new GosuSyntheticCompositeElement(GosuElementTypes.CLASS_DEFINITION);
rootFileNode.rawAddChildrenWithoutNotifications(classStmtNode);
CompositeElement synthModifierList = new GosuSyntheticCompositeElement(GosuElementTypes.ELEM_TYPE_ModifierListClause);
classStmtNode.rawAddChildrenWithoutNotifications(synthModifierList);
CompositeElement programClassDecl = new LightGosuIdentifierImpl(gosuProgram.getRelativeName());
classStmtNode.rawAddChildrenWithoutNotifications(programClassDecl);
IClassStatement cs = gosuProgram.getClassStatement();
addTokens(classStmtNode, cs, null);
final List topLevelStatements = getOrderedTopLevelStatements(gosuProgram);
for (Object toplevelThing : topLevelStatements) {
if (toplevelThing instanceof IParsedElement) {
final IParsedElement topLevelStmt = (IParsedElement) toplevelThing;
CompositeElement node = makeAstTree(classStmtNode, topLevelStmt);
if (node != null) {
// childNode can be null e.g., PropertyStatement (the corresponding function stmt is added inside makeAstTree())
classStmtNode.rawAddChildrenWithoutNotifications(node);
}
addTokens(classStmtNode, cs, topLevelStmt.getLocation());
} else {
final IToken token = (IToken) toplevelThing;
addToken(token.getTokenStart() >= cs.getLocation().getExtent()
? rootFileNode
: classStmtNode, token, token.getAfter(), false);
}
}
final IParseTree evaluateStatement = findEvaluateFunction(gosuProgram);
if (evaluateStatement != null) {
addTokens(classStmtNode, cs, evaluateStatement);
}
return rootFileNode;
}
public List<IParseTree> getChildrenSorted(@NotNull IParseTree tree) {
return Ordering.from(new Comparator<IParseTree>() {
public int compare(@NotNull IParseTree o1, @NotNull IParseTree o2) {
return o1.getOffset() - o2.getOffset();
}
}).immutableSortedCopy(tree.getChildren());
}
@NotNull
private List getOrderedTopLevelStatements(@NotNull IGosuProgram gsProg) {
@SuppressWarnings({"unchecked"})
final List elems = new SortedList(new Comparator() {
private int getOffset(@NotNull Object p) {
if (p instanceof IParsedElement) {
return ((IParsedElement) p).getLocation().getOffset();
} else {
return ((IToken) p).getTokenStart();
}
}
public int compare(@NotNull Object p1, @NotNull Object p2) {
return getOffset(p1) - getOffset(p2);
}
});
for (IParseTree childLoc : getChildrenSorted(gsProg.getClassStatement().getLocation())) {
final IParsedElement child = childLoc.getParsedElement();
if (child instanceof IFunctionStatement) {
IDynamicFunctionSymbol dfs = ((IFunctionStatement) child).getDynamicFunctionSymbol();
if (dfs instanceof IProgramClassFunctionSymbol) {
if (dfs.getDisplayName().equals("evaluate")) {
IStatement body = (IStatement) dfs.getValueDirectly();
if (body instanceof IStatementList) {
for (IStatement stmt : ((IStatementList) body).getStatements()) {
if ((!(stmt instanceof IReturnStatement) || stmt.getLocation() != null) &&
!(stmt instanceof IHideFieldNoOpStatement) && (!(stmt instanceof INoOpStatement) || !stmt.getTokens().isEmpty())) {
elems.add(stmt);
} else {
reportPotentiallyMissedTokens(elems, stmt);
}
}
// Add expressions that are direct children of the the body. This can happen with templates e.g., all the <%= xxx %> expressions
for (IParseTree csr : body.getLocation().getChildren()) {
if (csr.getParsedElement() instanceof IExpression) {
elems.add(csr.getParsedElement());
}
}
elems.addAll(body.getTokens());
IParsedElement otherStmtList = child.getLocation().getChildren().get(0).getParsedElement();
if (otherStmtList != body) {
elems.addAll(otherStmtList.getTokens());
}
} else {
elems.add(body);
}
}
} else {
elems.add(child);
}
} else {
elems.add(child);
}
}
for (IToken token : gsProg.getClassStatement().getClassFileStatement().getTokens()) {
elems.add(token);
}
return elems;
}
private void reportPotentiallyMissedTokens(List elems, @NotNull IParsedElement pe) {
if (pe.getLocation() != null) {
for (IParseTree child : pe.getLocation().getChildren()) {
reportPotentiallyMissedTokens(elems, child.getParsedElement());
}
}
for (IToken token : pe.getTokens()) {
throw new IllegalStateException("Unaccounted for token: " + token);
}
}
@Nullable
private CompositeElement makeAstTree(CompositeElement astParent, @NotNull IParsedElement peChild) {
CompositeElement astParentNew = makeAst(peChild);
CompositeElement result = astParentNew;
if (astParentNew == null) {
astParentNew = astParent;
}
addTokens(astParentNew, peChild, null);
for (IParseTree child : getChildrenSorted(peChild.getLocation())) {
CompositeElement childNode = makeAstTree(astParentNew, child.getParsedElement());
if (childNode != null) {
astParentNew.rawAddChildrenWithoutNotifications(childNode);
}
addTokens(astParentNew, peChild, child);
}
return result;
}
@NotNull
private CompositeElement makeAstForGosuClass(@NotNull IGosuClass gosuClass) {
if (gosuClass.isInterface()) {
return new GosuCompositeElement(GosuElementTypes.INTERFACE_DEFINITION);
} else if (gosuClass.isEnum()) {
return new GosuCompositeElement(GosuElementTypes.ENUM_DEFINITION);
} else if (gosuClass instanceof IGosuEnhancement) {
return new GosuCompositeElement(GosuElementTypes.ENHANCEMENT_DEFINITION);
} else if (gosuClass.getAllTypesInHierarchy().contains(JavaTypes.IANNOTATION())) {
return new GosuCompositeElement(GosuElementTypes.ANNOTATION_DEFINITION);
} else if (gosuClass.isAnonymous()) {
final GosuCompositeElement node = new GosuCompositeElement(GosuElementTypes.ANONYMOUS_CLASS_DEFINITION);
final CompositeElement programClassDecl = new LightGosuIdentifierImpl(gosuClass.getRelativeName());
node.rawAddChildrenWithoutNotifications(programClassDecl);
return node;
} else {
return new GosuCompositeElement(GosuElementTypes.CLASS_DEFINITION);
}
}
@Nullable
private CompositeElement makeAst(@NotNull IParsedElement pe) {
//## todo: at some point we'll want to support language injection for string templates
if (descendsFromTemplateStringLiteral(pe)) {
return null;
}
CompositeElement node;
if (pe instanceof INamespaceStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NamespaceStatement);
} else if (pe instanceof IClassFileStatement) {
return null;
} else if (pe instanceof IClassStatement) {
if (isProgram(pe)) {
return null;
}
node = makeAstForGosuClass(pe.getGosuClass());
} else if (pe instanceof IClassDeclaration) {
if (isProgram(pe)) {
return null;
}
if (pe.getLocation().getLength() == 0) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ClassDeclaration);
} else {
return null;
}
} else if (pe instanceof ITypeVariableExtendsListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeVariableExtendsListClause);
} else if (pe instanceof ISuperTypeClause) {
if (isProgram(pe)) {
return null;
}
node = new GosuCompositeElement(GosuElementTypes.EXTENDS_CLAUSE);
} else if (pe instanceof IInterfacesClause) {
if (isProgram(pe)) {
return null;
}
node = new GosuCompositeElement(GosuElementTypes.IMPLEMENTS_CLAUSE);
} else if (pe instanceof IFunctionStatement) {
if (isProgram(pe) &&
((IFunctionStatement) pe).getDynamicFunctionSymbol() instanceof IProgramClassFunctionSymbol) {
return null;
}
node = new GosuCompositeElement(GosuElementTypes.METHOD_DEFINITION);
} else if (pe instanceof IPropertyStatement) {
node = null;
} else if (pe instanceof IParameterListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ParameterListClause);
} else if (pe instanceof IModifierListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ModifierListClause);
} else if (pe instanceof IArgumentListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ArgumentListClause);
} else if (pe instanceof INameInDeclaration) {
if (isFieldProperty((INameInDeclaration) pe)) {
node = new GosuCompositeElement(GosuElementTypes.FIELD_PROPERTY);
String strPropName = ((INameInDeclaration)pe).getName();
if( strPropName == null || strPropName.length() == 0 ) {
node.rawAddChildrenWithoutNotifications( new LightGosuIdentifierImpl( "" ) );
}
} else if (isBlockParameter((INameInDeclaration) pe)) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ParameterDeclaration);
} else {
final String strName = ((INameInDeclaration) pe).getName();
final List<IToken> tokens = pe.getTokens();
if (Strings.isNullOrEmpty(strName) ||
tokens.isEmpty() ||
(tokens.size() == 1 && tokens.get(0).getType() != ISourceCodeTokenizer.TT_WORD && !Keyword.isValueKeyword( tokens.get( 0 ).getText() ) && !(pe.getParent() instanceof IFunctionStatement)) ||
pe.getParent() instanceof IConstructorStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NameInDeclaration);
} else {
// Skip over the NameInDeclaration and use the Identifier token directly (structurally easier to use with IJ if PsiIdentifier's parent is the Var or Method declaration)
node = null;
}
}
} else if (pe instanceof IStatementList) {
if (isProgram(pe) &&
pe.getParent() instanceof IFunctionStatement &&
((IFunctionStatement) pe.getParent()).getDynamicFunctionSymbol() instanceof IProgramClassFunctionSymbol) {
return null;
}
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_StatementList);
} else if (pe instanceof IVarStatement) {
IVarStatement stmt = (IVarStatement) pe;
if (stmt.isEnumConstant()) {
node = new GosuCompositeElement(GosuElementTypes.ENUM_CONSTANT);
} else if (stmt.isFieldDeclaration()) {
node = new GosuCompositeElement(GosuElementTypes.FIELD);
} else {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_VarStatement);
}
} else if (pe instanceof IAssignmentStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_AssignmentStatement);
} else if (pe instanceof IMemberAssignmentStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MemberAssignmentStatement);
} else if (pe instanceof IArrayAssignmentStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ArrayAssignmentStatement);
} else if (pe instanceof IMapAssignmentStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MapAssignmentStatement);
} else if (pe instanceof IMethodCallStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MethodCallStatement);
} else if (pe instanceof IBlockInvocationStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BlockInvocationStatement);
} else if (pe instanceof IBeanMethodCallStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BeanMethodCallStatement);
} else if (pe instanceof IReturnStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ReturnStatement);
} else if (pe instanceof IBreakStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BreakStatement);
} else if (pe instanceof IContinueStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ContinueStatement);
} else if (pe instanceof IIfStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_IfStatement);
} else if (pe instanceof IWhileStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_WhileStatement);
} else if (pe instanceof IDoWhileStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_DoWhileStatement);
} else if (pe instanceof IForEachStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ForEachStatement);
} else if (pe instanceof ISwitchStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_SwitchStatement);
} else if (pe instanceof ICaseClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_CaseClause);
} else if (pe instanceof ITryCatchFinallyStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TryCatchFinallyStatement);
} else if (pe instanceof ICatchClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_CatchClause);
} else if (pe instanceof IThrowStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ThrowStatement);
} else if (pe instanceof IUsingStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_UsingStatement);
} else if (pe instanceof IEvalStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_EvalStatement);
} else if (pe instanceof ISyntheticFunctionStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_SyntheticFunctionStatement);
} else if (pe instanceof ISyntheticMemberAccessStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_SyntheticMemberAccessStatement);
} else if (pe instanceof INoOpStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NoOpStatement);
} else if (pe instanceof IClasspathStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ClasspathStatement);
} else if (pe instanceof IUsesStatementList) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_UsesStatementList);
} else if (pe instanceof IUsesStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_UsesStatement);
} else if (pe instanceof IIdentifierExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_IdentifierExpression);
} else if (pe instanceof ITypeAsExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeAsExpression);
} else if (pe instanceof ITypeIsExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeIsExpression);
} else if (pe instanceof ITypeOfExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeOfExpression);
} else if (pe instanceof IStaticTypeOfExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_StaticTypeOfExpression);
} else if (pe instanceof IStringLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_StringLiteral);
} else if (pe instanceof ICharLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_CharLiteral);
} else if (pe instanceof INumericLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NumericLiteral);
} else if (pe instanceof ITypeLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeLiteral);
} else if (pe instanceof ITypeParameterListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeParameterListClause);
} else if (pe instanceof ITypeVariableDefinitionExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeVariableDefinitionExpression);
} else if (pe instanceof ITypeVariableListClause) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TypeVariableListClause);
} else if (pe instanceof IBooleanLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BooleanLiteral);
} else if (pe instanceof IUnaryExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_UnaryExpression);
} else if (pe instanceof IUnaryNotPlusMinusExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_UnaryNotPlusMinusExpression);
} else if (pe instanceof IEqualityExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_EqualityExpression);
} else if (pe instanceof IIdentityExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_IdentityExpression);
} else if (pe instanceof IRelationalExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_RelationalExpression);
} else if (pe instanceof IConditionalOrExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ConditionalOrExpression);
} else if (pe instanceof IConditionalAndExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ConditionalAndExpression);
} else if (pe instanceof IAdditiveExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_AdditiveExpression);
} else if (pe instanceof IMultiplicativeExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MultiplicativeExpression);
} else if (pe instanceof IBitshiftExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BitshiftExpression);
} else if (pe instanceof IBitwiseOrExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BitwiseOrExpression);
} else if (pe instanceof IBitwiseXorExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BitwiseXorExpression);
} else if (pe instanceof IBitwiseAndExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BitwiseAndExpression);
} else if (pe instanceof IBeanMethodCallExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BeanMethodCallExpression);
} else if (pe instanceof IMethodCallExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MethodCallExpression);
} else if (pe instanceof IMemberExpansionExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MemberExpansionAccess);
} else if (pe instanceof IMemberAccessExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MemberAccess);
} else if (pe instanceof IFieldAccessExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_FieldAccess);
} else if (pe instanceof IAnnotationExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_AnnotationExpression);
} else if (pe instanceof INewExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NewExpression);
} else if (pe instanceof INewStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NewStatement);
} else if (pe instanceof IEvalExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_EvalExpression);
} else if (pe instanceof IQueryExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_QueryExpression);
} else if (pe instanceof IConditionalTernaryExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ConditionalTernaryExpression);
} else if (pe instanceof IArrayAccessExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ArrayAccess);
} else if (pe instanceof IMapAccessExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MapAccess);
} else if (pe instanceof IIntervalExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_IntervalExpression);
} else if (pe instanceof IParenthesizedExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ParenthesizedExpression);
} else if (pe instanceof INullExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NullExpression);
} else if (pe instanceof IBlockExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BlockExpression);
} else if (pe instanceof IObjectLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ObjectLiteralExpression);
} else if (pe instanceof ITemplateStringLiteral) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_TemplateStringLiteral);
} else if (pe instanceof IExistsExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ExistsExpression);
} else if (pe instanceof IBlockInvocation) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_BlockInvocation);
} else if (pe instanceof IFeatureLiteralExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_FeatureLiteral);
} else if (pe instanceof IParameterDeclaration) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ParameterDeclaration);
} else if (pe instanceof ICollectionInitializerExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_CollectionInitializerExpression);
} else if (pe instanceof IMapInitializerExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_MapInitializerExpression);
} else if (pe instanceof IObjectInitializerExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_ObjectInitializerExpression);
} else if (pe instanceof INotAStatement) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NotAStatement);
} else if (pe instanceof INotAWordExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_NotAWordExpression);
} else if (pe instanceof ILocalVarDeclaration) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_LocalVarDeclaration);
} else if (pe instanceof IDirectiveExpression) {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE_DirectiveExpression);
} else {
node = new GosuCompositeElement(GosuElementTypes.ELEM_TYPE____UnhandledParsedElement);
//throw new UnsupportedOperationException( "AST Transformer not yet implemented for: " + pe.getClass().getName() );
}
return node;
}
private boolean isFieldProperty(@NotNull INameInDeclaration pe) {
final IParsedElement parent = pe.getParent();
if (parent instanceof IVarStatement) {
final IVarStatement varStatement = (IVarStatement) parent;
final String identifierName = varStatement.getIdentifierName();
return varStatement.isFieldDeclaration() &&
(identifierName == null ||
(!pe.getName().equals(identifierName.toString()) &&
// _duplicate_<id> is indicative of a duplicate variable name, which distinguishes all duplicates from the first of the duplicates
!(identifierName.toString().endsWith("_duplicate_" + pe.getName()))));
}
return false;
}
private boolean isBlockParameter(@NotNull INameInDeclaration pe) {
final IParsedElement parent = pe.getParent();
return parent instanceof IParameterListClause && parent.getParent() instanceof IBlockExpression;
}
private boolean descendsFromTemplateStringLiteral(@Nullable IParsedElement pe) {
if (pe == null) {
return false;
}
if (pe.getParent() instanceof ITemplateStringLiteral) {
return true;
}
return descendsFromTemplateStringLiteral(pe.getParent());
}
private boolean isProgram(@NotNull IParsedElement pe) {
return pe.getGosuClass() instanceof IGosuProgram;
}
private void addTokens(@NotNull CompositeElement node, @NotNull IParsedElement pe, IParseTree after) {
for (IToken token : pe.getTokens()) {
addToken(node, token, after, pe instanceof INameInDeclaration );
}
}
private void addToken( @NotNull CompositeElement node, @NotNull IToken token, @Nullable IParseTree after, boolean bIdentfier ) {
final int tokenType = token.getType();
final String tokenText = token.getText();
final IParseTree tokenAfter = token.getAfter();
if (after == tokenAfter || (after != null && after.isAncestor(tokenAfter))) {
if (tokenType == ISourceCodeTokenizer.TT_WHITESPACE) {
node.rawAddChildrenWithoutNotifications(ASTFactory.leaf(GosuTokenTypes.TT_WHITESPACE, tokenText));
} else if (tokenType == ISourceCodeTokenizer.TT_EOF) {
// skip
} else {
final IElementType elementType = GosuTokenTypes.getTypeFrom(token);
if (tokenType == ISourceCodeTokenizer.TT_WORD || bIdentfier || tokenText.equals("void")) {
node.rawAddChildrenWithoutNotifications(new GosuIdentifierImpl(elementType, tokenText));
} else {
if (elementType == GosuTokenTypes.TT_COMMENT_MULTILINE && tokenText.startsWith("/**")) {
node.rawAddChildrenWithoutNotifications(new PsiDocCommentImpl(tokenText));
} else {
if( elementType instanceof IGosuElementType ) {
if( elementType == GosuTokenTypes.TT_COMMENT_MULTILINE ||
elementType == GosuTokenTypes.TT_COMMENT_LINE ) {
node.rawAddChildrenWithoutNotifications( new GosuCommentImpl( elementType, tokenText ) );
}
else {
node.rawAddChildrenWithoutNotifications( new GosuTokenImpl( elementType, tokenText ) );
}
}
else {
node.rawAddChildrenWithoutNotifications(ASTFactory.leaf(elementType, tokenText));
}
}
}
}
}
}
@Nullable
private IParseTree findEvaluateFunction(@NotNull IGosuProgram program) {
IClassStatement classStatement = program.getClassStatement();
IParseTree location = classStatement.getLocation();
if(location==null){
return null;
}
for (IParseTree pt : location.getChildren()) {
if (isEvaluateFunction(pt.getParsedElement())) {
return pt;
}
}
return null;
}
private boolean isEvaluateFunction(@NotNull IParsedElement pe) {
if (pe instanceof IFunctionStatement) {
final IDynamicFunctionSymbol dfs = ((IFunctionStatement) pe).getDynamicFunctionSymbol();
if (dfs instanceof IProgramClassFunctionSymbol) {
if (dfs.getDisplayName().equals("evaluate")) {
return true;
}
}
}
return false;
}
}