blob: 753a5e178cf7486ff0573f3e5c96a812b5c99f83 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Red Hat, Inc.
* 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:
* Red Hat Inc. - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.wst.jsdt.core.dom;
import java.util.Iterator;
import java.util.List;
import org.eclipse.wst.jsdt.core.dom.Assignment.Operator;
import org.eclipse.wst.jsdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.wst.jsdt.core.dom.ObjectLiteralField.FieldKind;
import com.google.javascript.jscomp.parsing.parser.IdentifierToken;
import com.google.javascript.jscomp.parsing.parser.Token;
import com.google.javascript.jscomp.parsing.parser.TokenType;
import com.google.javascript.jscomp.parsing.parser.trees.ArrayLiteralExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ArrayPatternTree;
import com.google.javascript.jscomp.parsing.parser.trees.AssignmentRestElementTree;
import com.google.javascript.jscomp.parsing.parser.trees.BinaryOperatorTree;
import com.google.javascript.jscomp.parsing.parser.trees.BlockTree;
import com.google.javascript.jscomp.parsing.parser.trees.BreakStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.CallExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.CaseClauseTree;
import com.google.javascript.jscomp.parsing.parser.trees.CatchTree;
import com.google.javascript.jscomp.parsing.parser.trees.ClassDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.CommaExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.Comment;
import com.google.javascript.jscomp.parsing.parser.trees.ComputedPropertyDefinitionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ComputedPropertyGetterTree;
import com.google.javascript.jscomp.parsing.parser.trees.ComputedPropertyMemberVariableTree;
import com.google.javascript.jscomp.parsing.parser.trees.ComputedPropertyMethodTree;
import com.google.javascript.jscomp.parsing.parser.trees.ComputedPropertySetterTree;
import com.google.javascript.jscomp.parsing.parser.trees.ConditionalExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ContinueStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.DebuggerStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.DefaultClauseTree;
import com.google.javascript.jscomp.parsing.parser.trees.DefaultParameterTree;
import com.google.javascript.jscomp.parsing.parser.trees.DoWhileStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.EmptyStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.ExportDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.ExportSpecifierTree;
import com.google.javascript.jscomp.parsing.parser.trees.ExpressionStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.ForInStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.ForOfStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.ForStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.FunctionDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.GetAccessorTree;
import com.google.javascript.jscomp.parsing.parser.trees.IdentifierExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.IfStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.ImportDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.ImportSpecifierTree;
import com.google.javascript.jscomp.parsing.parser.trees.LabelledStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.LiteralExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.MemberExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.MemberLookupExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ModuleImportTree;
import com.google.javascript.jscomp.parsing.parser.trees.NewExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.NullTree;
import com.google.javascript.jscomp.parsing.parser.trees.ObjectLiteralExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ObjectPatternTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParenExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTree;
import com.google.javascript.jscomp.parsing.parser.trees.ParseTreeType;
import com.google.javascript.jscomp.parsing.parser.trees.PostfixExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ProgramTree;
import com.google.javascript.jscomp.parsing.parser.trees.PropertyNameAssignmentTree;
import com.google.javascript.jscomp.parsing.parser.trees.RestParameterTree;
import com.google.javascript.jscomp.parsing.parser.trees.ReturnStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.SetAccessorTree;
import com.google.javascript.jscomp.parsing.parser.trees.SpreadExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.SuperExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.SwitchStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.TemplateLiteralExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.TemplateLiteralPortionTree;
import com.google.javascript.jscomp.parsing.parser.trees.TemplateSubstitutionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ThisExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.ThrowStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.TryStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.TypeNameTree;
import com.google.javascript.jscomp.parsing.parser.trees.UnaryExpressionTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationListTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableDeclarationTree;
import com.google.javascript.jscomp.parsing.parser.trees.VariableStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.WhileStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.WithStatementTree;
import com.google.javascript.jscomp.parsing.parser.trees.YieldExpressionTree;
import com.google.javascript.jscomp.parsing.parser.util.SourceRange;
/**
* Converts closure compiler's IR model to DOM AST.
*
* @author Gorkem Ercan
*
*/
@SuppressWarnings("unchecked")
public class ClosureCompilerASTConverter {
private static final String KEYWORD_SUPER = "super"; //$NON-NLS-1$
private static final boolean DEBUG = false;
private final AST ast;
private final List<Comment> comments;
private Comment currentComment;
private final Iterator<Comment> nextCommentIter;
public ClosureCompilerASTConverter(AST t, List<Comment> comment){
this.ast = t;
this.comments = comment;
this.nextCommentIter = comments.iterator();
this.currentComment = nextCommentIter.hasNext() ? nextCommentIter.next() : null;
}
public ASTNode transform(StructuralPropertyDescriptor property, ParseTree tree) {
if(DEBUG){
System.out.println(">> transform:: property : "+ property +" tree: "+tree); //$NON-NLS-1$//$NON-NLS-2$
}
if(tree == null )
return null;
ASTNode node = process(property, tree);
if (node == null )
return null;
setSourceRange(node, tree);
if(DEBUG){
System.out.println("<< transform:: tree: "+tree +" --> node:"+ node); //$NON-NLS-1$ //$NON-NLS-2$
}
return node;
}
/**
* @param tree
* @param node
*/
private <T extends ASTNode> void attachJSDoc(ParseTree tree, BodyDeclaration node) {
Comment info = handleJsDoc(tree);
if (info != null && info.isJsDoc()) {
JSdoc doc = ast.newJSdoc();
doc.setComment(info.value);
doc.setSourceRange(info.location.start.offset, info.location.end.offset - info.location.start.offset);
node.setJavadoc(doc);
}
}
/**
* @param tree
* @param node
*/
private <T extends ASTNode> void attachJSDoc(ParseTree tree, VariableDeclarationStatement node) {
Comment info = handleJsDoc(tree);
if (info != null && info.isJsDoc()) {
JSdoc doc = ast.newJSdoc();
doc.setComment(info.value);
doc.setSourceRange(info.location.start.offset, info.location.end.offset - info.location.start.offset);
node.setJavadoc(doc);
}
}
private InfixExpression.Operator convertBinaryOperator(Token operator) {
return InfixExpression.Operator.toOperator(operator.toString());
}
private VariableKind convertVariableKind(TokenType token){
switch(token){
case LET : return VariableKind.LET;
case CONST : return VariableKind.CONST;
// Returns VAR by default
default: return VariableKind.VAR;
}
}
private boolean notNullStatement(ParseTree tree){
return tree.type != ParseTreeType.NULL;
}
private ASTNode process(StructuralPropertyDescriptor property, ParseTree node) {
switch (node.type) {
case BINARY_OPERATOR:
return processBinaryExpression(node.asBinaryOperator());
case ARRAY_LITERAL_EXPRESSION:
return processArrayLiteral(node.asArrayLiteralExpression());
case TEMPLATE_LITERAL_EXPRESSION:
return processTemplateLiteral(node.asTemplateLiteralExpression());
case TEMPLATE_LITERAL_PORTION:
return processTemplateLiteralPortion(node.asTemplateLiteralPortion());
case TEMPLATE_SUBSTITUTION:
return processTemplateSubstitution(node.asTemplateSubstitution());
case UNARY_EXPRESSION:
return processUnaryExpression(node.asUnaryExpression());
case BLOCK:
return processBlock(node.asBlock());
case BREAK_STATEMENT:
return processBreakStatement(node.asBreakStatement());
case CALL_EXPRESSION:
return processFunctionCall(node.asCallExpression());
case SWITCH_STATEMENT:
return processSwitchStatement(node.asSwitchStatement());
case CASE_CLAUSE:
return processSwitchCase(node.asCaseClause());
case DEFAULT_CLAUSE:
return processSwitchDefault(node.asDefaultClause());
case CATCH:
return processCatchClause(node.asCatch());
case CONTINUE_STATEMENT:
return processContinueStatement(node.asContinueStatement());
case DO_WHILE_STATEMENT:
return processDoLoop(node.asDoWhileStatement());
case EMPTY_STATEMENT:
return processEmptyStatement(node.asEmptyStatement());
case EXPRESSION_STATEMENT:
return processExpressionStatement(node.asExpressionStatement());
case DEBUGGER_STATEMENT:
return processDebuggerStatement(node.asDebuggerStatement());
case THIS_EXPRESSION:
return processThisExpression(node.asThisExpression());
case FOR_STATEMENT:
return processForLoop(node.asForStatement());
case FOR_IN_STATEMENT:
return processForInLoop(node.asForInStatement());
case FUNCTION_DECLARATION:
return processFunction(property, node.asFunctionDeclaration());
case MEMBER_LOOKUP_EXPRESSION:
return processElementGet(node.asMemberLookupExpression());
case MEMBER_EXPRESSION:
return processPropertyGet(property, node.asMemberExpression());
case CONDITIONAL_EXPRESSION:
return processConditionalExpression(node.asConditionalExpression());
case IF_STATEMENT:
return processIfStatement(node.asIfStatement());
case LABELLED_STATEMENT:
return processLabeledStatement(node.asLabelledStatement());
case PAREN_EXPRESSION:
return processParenthesizedExpression(node.asParenExpression());
case IDENTIFIER_EXPRESSION:
return processName(property, node.asIdentifierExpression());
case NEW_EXPRESSION:
return processNewExpression(node.asNewExpression());
case OBJECT_LITERAL_EXPRESSION:
return processObjectLiteral(node.asObjectLiteralExpression());
case COMPUTED_PROPERTY_GETTER:
return processComputedPropertyGetter(property, node.asComputedPropertyGetter());
case COMPUTED_PROPERTY_SETTER:
return processComputedPropertySetter(property, node.asComputedPropertySetter());
case COMPUTED_PROPERTY_METHOD:
return processComputedPropertyMethod(property, node.asComputedPropertyMethod());
case COMPUTED_PROPERTY_DEFINITION:
case COMPUTED_PROPERTY_MEMBER_VARIABLE:
// Handled on processObjectLiteral should never happen here for legal JS
return null;
case RETURN_STATEMENT:
return processReturnStatement(node.asReturnStatement());
case POSTFIX_EXPRESSION:
return processPostfixExpression(node.asPostfixExpression());
case PROGRAM:
return processAstRoot(node.asProgram());
case LITERAL_EXPRESSION: // STRING, NUMBER, TRUE, FALSE, NULL, REGEXP
return processLiteralExpression(node.asLiteralExpression());
case THROW_STATEMENT:
return processThrowStatement(node.asThrowStatement());
case TRY_STATEMENT:
return processTryStatement(node.asTryStatement());
case VARIABLE_STATEMENT: // var const let
return processVariableStatement(node.asVariableStatement());
case VARIABLE_DECLARATION_LIST:
return processVariableDeclarationList(node.asVariableDeclarationList());
case VARIABLE_DECLARATION:
return processVariableDeclaration(node.asVariableDeclaration());
case WHILE_STATEMENT:
return processWhileLoop(node.asWhileStatement());
case WITH_STATEMENT:
return processWithStatement(node.asWithStatement());
case COMMA_EXPRESSION:
return processCommaExpression(node.asCommaExpression());
case NULL: // this is not the null literal
return processNull(node.asNull());
case FINALLY:
return transform(property, node.asFinally().block);
case MISSING_PRIMARY_EXPRESSION:
// DOM AST provides a syntactically plausible initial value to required
// properties skip processing this node type.
return null;
case PROPERTY_NAME_ASSIGNMENT:
return processPropertyNameAssignment(node.asPropertyNameAssignment());
case GET_ACCESSOR:
return processGetAccessor(property, node.asGetAccessor());
case SET_ACCESSOR:
return processSetAccessor(property, node.asSetAccessor());
case FORMAL_PARAMETER_LIST:
//Should be handled on processFunction
// if we end up here it is probably because of tolerant parsing
return null;
case CLASS_DECLARATION:
return processClassDeclaration(property, node.asClassDeclaration());
case SUPER_EXPRESSION:
return processSuper(node.asSuperExpression());
case YIELD_EXPRESSION:
return processYield(node.asYieldStatement());
case FOR_OF_STATEMENT:
return processForOf(node.asForOfStatement());
case EXPORT_DECLARATION:
return processExportDecl(node.asExportDeclaration());
case EXPORT_SPECIFIER:
return processExportSpec(node.asExportSpecifier());
case IMPORT_DECLARATION:
return processImportDecl(node.asImportDeclaration());
case IMPORT_SPECIFIER:
return processImportSpec(node.asImportSpecifier());
case MODULE_IMPORT:
return processModuleImport(node.asModuleImport());
case ARRAY_PATTERN:
return processArrayPattern(property,node.asArrayPattern());
case OBJECT_PATTERN:
return processObjectPattern(property,node.asObjectPattern());
case ASSIGNMENT_REST_ELEMENT:
return processAssignmentRestElement(node.asAssignmentRestElement());
// case COMPREHENSION:
// return processComprehension(node.asComprehension());
// case COMPREHENSION_FOR:
// return processComprehensionFor(node.asComprehensionFor());
// case COMPREHENSION_IF:
// return processComprehensionIf(node.asComprehensionIf());
case DEFAULT_PARAMETER:
return processDefaultParameter(property, node.asDefaultParameter());
case REST_PARAMETER:
return processRestParameter(property, node.asRestParameter());
case SPREAD_EXPRESSION:
return processSpreadExpression(node.asSpreadExpression());
// ES6 Typed
case TYPE_NAME:
return processTypeName(node.asTypeName());
// case TYPED_PARAMETER:
// return processTypedParameter(node.asTypedParameter());
// case OPTIONAL_PARAMETER:
// return processOptionalParameter(node.asOptionalParameter());
// case PARAMETERIZED_TYPE_TREE:
// return processParameterizedType(node.asParameterizedType());
// case ARRAY_TYPE:
// return processArrayType(node.asArrayType());
// case RECORD_TYPE:
// return processRecordType(node.asRecordType());
// case UNION_TYPE:
// return processUnionType(node.asUnionType());
// case FUNCTION_TYPE:
// return processFunctionType(node.asFunctionType());
// case TYPE_QUERY:
// return processTypeQuery(node.asTypeQuery());
// case GENERIC_TYPE_LIST:
// return processGenericTypeList(node.asGenericTypeList());
// case MEMBER_VARIABLE:
// return processMemberVariable(node.asMemberVariable());
//
// case INTERFACE_DECLARATION:
// return processInterfaceDeclaration(node.asInterfaceDeclaration());
// case ENUM_DECLARATION:
// return processEnumDeclaration(node.asEnumDeclaration());
//
// case TYPE_ALIAS:
// return processTypeAlias(node.asTypeAlias());
// case AMBIENT_DECLARATION:
// return processAmbientDeclaration(node.asAmbientDeclaration());
// case NAMESPACE_DECLARATION:
// return processNamespaceDeclaration(node.asNamespaceDeclaration());
//
// case INDEX_SIGNATURE:
// return processIndexSignature(node.asIndexSignature());
// case CALL_SIGNATURE:
// return processCallSignature(node.asCallSignature());
case ARGUMENT_LIST:
default:
break;
}
return processIllegalToken(node);
}
/**
* @param asComputedPropertyMethod
* @return
*/
private ASTNode processComputedPropertyMethod(StructuralPropertyDescriptor property, ComputedPropertyMethodTree tree) {
FunctionDeclaration $ = ast.newFunctionDeclaration();
FunctionDeclarationTree methodTree= tree.method.asFunctionDeclaration();
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY, methodTree.functionBody);
transformAndSetProperty($,FunctionDeclaration.METHOD_NAME_PROPERTY, tree.property);
if(methodTree.isStatic){
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
}
return adjustFunctionDeclarationToProperty(property,$);
}
/**
* @param asComputedPropertySetter
* @return
*/
private ASTNode processComputedPropertySetter(StructuralPropertyDescriptor property, ComputedPropertySetterTree tree) {
FunctionDeclaration $ = ast.newFunctionDeclaration();
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY,tree.body);
transformAndSetProperty($,FunctionDeclaration.METHOD_NAME_PROPERTY,tree.property);
$.modifiers().add(ast.newModifier(ModifierKeyword.SET_KEYWORD));
if(tree.isStatic){
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
}
return adjustFunctionDeclarationToProperty(property,$);
}
/**
* @param asComputedPropertyGetter
* @return
*/
private ASTNode processComputedPropertyGetter(StructuralPropertyDescriptor property, ComputedPropertyGetterTree tree) {
FunctionDeclaration $ = ast.newFunctionDeclaration();
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY,tree.body);
transformAndSetProperty($,FunctionDeclaration.METHOD_NAME_PROPERTY,tree.property);
$.modifiers().add(ast.newModifier(ModifierKeyword.GET_KEYWORD));
if(tree.isStatic){
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
}
return adjustFunctionDeclarationToProperty(property,$);
}
/**
* @param asArrayLiteralExpression
* @return
*/
private ASTNode processArrayLiteral(ArrayLiteralExpressionTree tree) {
ArrayInitializer $ = ast.newArrayInitializer();
for ( ParseTree pe : tree.elements) {
if(notNullStatement(pe))
$.expressions().add(transform(ArrayInitializer.EXPRESSIONS_PROPERTY,pe));
}
return $;
}
/**
* @param asArrayPattern
* @return
*/
private ASTNode processArrayPattern(StructuralPropertyDescriptor property, ArrayPatternTree tree) {
ArrayName $ = ast.newArrayName();
for(ParseTree child: tree.elements){
if(notNullStatement(child))
$.elements().add(transform(ArrayName.ELEMENTS_PROPERTY,child));
}
Class<?> claz = classForProperty(property);
if(claz.isAssignableFrom(SingleVariableDeclaration.class)){
SingleVariableDeclaration svd = ast.newSingleVariableDeclaration();
svd.setPattern($);
return svd;
}
return $;
}
/**
* @param asAssignmentRestElement
* @return
*/
private ASTNode processAssignmentRestElement(AssignmentRestElementTree tree) {
RestElementName $ = ast.newRestElementName();
if(tree.identifier != null){
$.setArgument(transformLabelName(tree.identifier));
}
return $;
}
/**
* @param asProgram
* @return
*/
private ASTNode processAstRoot(ProgramTree tree) {
JavaScriptUnit $ = ast.newJavaScriptUnit();
for (ParseTree child : tree.sourceElements) {
switch (child.type) {
case EXPORT_DECLARATION:
$.exports().add(transform(JavaScriptUnit.EXPORTS_PROPERTY,child));
break;
case IMPORT_DECLARATION :
$.imports().add(transform(JavaScriptUnit.IMPORTS_PROPERTY,child));
break;
default :
$.statements().add(transform(JavaScriptUnit.STATEMENTS_PROPERTY,child));
break;
}
}
return $;
}
/**
* @param asBinaryOperator
* @return
*/
private ASTNode processBinaryExpression(BinaryOperatorTree tree) {
Operator assignOp = Assignment.Operator.toOperator(tree.operator.toString());
if(assignOp != null){
Assignment $ = ast.newAssignment();
safeSetProperty($, Assignment.OPERATOR_PROPERTY,assignOp);
transformAndSetProperty($,Assignment.LEFT_HAND_SIDE_PROPERTY,tree.left);
transformAndSetProperty($,Assignment.RIGHT_HAND_SIDE_PROPERTY,tree.right);
return $;
}
InfixExpression $ = ast.newInfixExpression();
safeSetProperty($,InfixExpression.OPERATOR_PROPERTY,convertBinaryOperator(tree.operator));
transformAndSetProperty($,InfixExpression.LEFT_OPERAND_PROPERTY, tree.left);
transformAndSetProperty($,InfixExpression.RIGHT_OPERAND_PROPERTY, tree.right);
return $;
}
/**
* @param asBlock
* @return
*/
private ASTNode processBlock(BlockTree tree) {
Block $ = ast.newBlock();
for (ParseTree pt : tree.statements) {
if(notNullStatement(pt))
$.statements().add(transform(Block.STATEMENTS_PROPERTY, pt));
}
return $;
}
/**
* @param asBreakStatement
* @return
*/
private ASTNode processBreakStatement(BreakStatementTree tree) {
BreakStatement $ = ast.newBreakStatement();
if(tree.name != null)
$.setLabel(transformLabelName(tree.name));
return $;
}
/**
* @param asCatch
* @return
*/
private ASTNode processCatchClause(CatchTree tree) {
CatchClause $ = ast.newCatchClause();
transformAndSetProperty($, CatchClause.EXCEPTION_PROPERTY,tree.exception);
transformAndSetProperty($,CatchClause.BODY_PROPERTY,tree.catchBody);
return $;
}
/**
* @param asClassDeclaration
* @return
*/
private ASTNode processClassDeclaration(StructuralPropertyDescriptor property, ClassDeclarationTree tree) {
TypeDeclaration $ = ast.newTypeDeclaration();
if(tree.name != null){
$.setName(transformLabelName(tree.name));
}
transformAndSetProperty($,TypeDeclaration.SUPERCLASS_EXPRESSION_PROPERTY,tree.superClass);
for(ParseTree child : tree.elements){
final ASTNode declaration = transform(TypeDeclaration.BODY_DECLARATIONS_PROPERTY,child);
// We can get empty statements from closure compiler due to tolerant parsing
if(declaration instanceof EmptyStatement)
continue;
$.bodyDeclarations().add(declaration);
}
attachJSDoc(tree,$);
Class<?> claz = classForProperty(property);
if(claz.isAssignableFrom(Expression.class)){
return ast.newTypeDeclarationExpression($);
}
if(claz.isAssignableFrom(Statement.class)){
return ast.newTypeDeclarationStatement($);
}
return $;
}
/**
* @param asCommaExpression
* @return
*/
private ASTNode processCommaExpression(CommaExpressionTree tree) {
ListExpression $ = ast.newListExpression();
for(ParseTree expr : tree.expressions){
$.expressions().add(transform(ListExpression.EXPRESSIONS_PROPERTY,expr));
}
return $;
}
/**
* @param asConditionalExpression
* @return
*/
private ASTNode processConditionalExpression(ConditionalExpressionTree tree) {
ConditionalExpression $ = ast.newConditionalExpression();
transformAndSetProperty($,ConditionalExpression.EXPRESSION_PROPERTY,tree.condition);
transformAndSetProperty($,ConditionalExpression.THEN_EXPRESSION_PROPERTY,tree.left);
transformAndSetProperty($,ConditionalExpression.ELSE_EXPRESSION_PROPERTY,tree.right);
return $;
}
/**
* @param asContinueStatement
* @return
*/
private ASTNode processContinueStatement(ContinueStatementTree tree) {
ContinueStatement $ = ast.newContinueStatement();
if(tree.name != null)
$.setLabel(transformLabelName(tree.name));
return $;
}
/**
* @param asDebuggerStatement
* @return
*/
private ASTNode processDebuggerStatement(DebuggerStatementTree tree) {
return ast.newDebuggerStatement();
}
/**
* @param asDefaultParameter
* @return
*/
private ASTNode processDefaultParameter(StructuralPropertyDescriptor property, DefaultParameterTree tree) {
// TODO: handle default values properly. DOM ast does not have support
// for it and needs to be enhanced.
return transform(property,tree.lhs);
}
/**
* @param asDoWhileStatement
* @return
*/
private ASTNode processDoLoop(DoWhileStatementTree tree) {
DoStatement $ = ast.newDoStatement();
transformAndSetProperty($,DoStatement.EXPRESSION_PROPERTY,tree.condition);
transformAndSetProperty($,DoStatement.BODY_PROPERTY,tree.body);
return $;
}
/**
* @param asMemberLookupExpression
* @return
*/
private ASTNode processElementGet(MemberLookupExpressionTree tree) {
ArrayAccess $ = ast.newArrayAccess();
transformAndSetProperty($,ArrayAccess.INDEX_PROPERTY,tree.memberExpression);
transformAndSetProperty($,ArrayAccess.ARRAY_PROPERTY,tree.operand);
return $;
}
/**
* @param asEmptyStatement
* @return
*/
private ASTNode processEmptyStatement(EmptyStatementTree tree) {
return ast.newEmptyStatement();
}
/**
* @param asExportDeclaration
* @return
*/
private ASTNode processExportDecl(ExportDeclarationTree tree) {
ExportDeclaration $ = ast.newExportDeclaration();
$.setAll(tree.isExportAll);
$.setDefault(tree.isDefault);
if(tree.declaration != null)
{
if(tree.declaration.type == ParseTreeType.VARIABLE_DECLARATION_LIST){
VariableDeclarationListTree vdTree = tree.declaration.asVariableDeclarationList();
VariableDeclarationStatement statement = ast.newVariableDeclarationStatement();
for(ParseTree child : vdTree.declarations){
statement.fragments().add(transform(VariableDeclarationStatement.FRAGMENTS_PROPERTY,child));
}
$.setDeclaration(statement);
}else{
transformAndSetProperty($,ExportDeclaration.DECLARATION_PROPERTY,tree.declaration);
}
}
if (tree.exportSpecifierList != null) {
for (ParseTree spec : tree.exportSpecifierList) {
$.specifiers().add(transform(ExportDeclaration.SPECIFIERS_PROPERTY,spec));
}
}
if(tree.from != null){
$.setSource(transformStringLiteral(tree.from));
}
return $;
}
/**
* @param asExportSpecifier
* @return
*/
private ASTNode processExportSpec(ExportSpecifierTree tree) {
ModuleSpecifier $ = ast.newModuleSpecifier();
if(tree.importedName != null){
$.setLocal(transformLabelName(tree.importedName));
}
if(tree.destinationName != null)
$.setDiscoverableName(transformLabelName(tree.destinationName));
return $;
}
/**
* @param asExpressionStatement
* @return
*/
private ASTNode processExpressionStatement(ExpressionStatementTree tree ) {
ExpressionStatement $ = ast.newExpressionStatement();
transformAndSetProperty($,ExpressionStatement.EXPRESSION_PROPERTY,tree.expression);
return $;
}
/**
* @param asForInStatement
* @return
*/
private ASTNode processForInLoop(ForInStatementTree tree) {
ForInStatement $ = ast.newForInStatement();
transformAndSetProperty($, ForInStatement.BODY_PROPERTY,tree.body);
transformAndSetProperty($, ForInStatement.ITERATION_VARIABLE_PROPERTY,tree.initializer);
transformAndSetProperty($, ForInStatement.COLLECTION_PROPERTY,tree.collection);
return $;
}
/**
* @param asForStatement
* @return
*/
private ASTNode processForLoop(ForStatementTree tree) {
ForStatement $ = ast.newForStatement();
transformAndSetProperty($, ForStatement.BODY_PROPERTY, tree.body);
if(notNullStatement(tree.condition))
transformAndSetProperty($,ForStatement.EXPRESSION_PROPERTY,tree.condition);
if(notNullStatement(tree.initializer)){
if(tree.initializer.type == ParseTreeType.VARIABLE_DECLARATION_LIST){
VariableDeclarationListTree listTree = tree.initializer.asVariableDeclarationList();
int startPosition =listTree.location.start.offset;
final VariableDeclarationExpression vd = ast.newVariableDeclarationExpression();
vd.setKind(convertVariableKind(listTree.declarationType));
for(ParseTree child : listTree.declarations){
vd.fragments().add(transform(VariableDeclarationExpression.FRAGMENTS_PROPERTY,child));
//The start position for the very first expression should start from list Tree.
if(startPosition <0){
startPosition = child.location.start.offset;
}
vd.setSourceRange(startPosition, child.location.end.offset -startPosition);
startPosition = -1;
}
$.initializers().add(vd);
}else{
$.initializers().add(transform(ForStatement.INITIALIZERS_PROPERTY, tree.initializer));
}
}
if( notNullStatement(tree.increment))
$.updaters().add(transform(ForStatement.UPDATERS_PROPERTY, tree.increment));
return $;
}
/**
* @param asForOfStatement
* @return
*/
private ASTNode processForOf(ForOfStatementTree tree) {
ForOfStatement $ = ast.newForOfStatement();
transformAndSetProperty($,ForOfStatement.BODY_PROPERTY, tree.body);
transformAndSetProperty($,ForOfStatement.ITERATION_VARIABLE_PROPERTY,tree.initializer);
transformAndSetProperty($,ForOfStatement.COLLECTION_PROPERTY,tree.collection);
return $;
}
/**
* @param asFunctionDeclaration
* @return
*/
private ASTNode processFunction(StructuralPropertyDescriptor property, FunctionDeclarationTree tree) {
if(tree.kind == FunctionDeclarationTree.Kind.ARROW){
ArrowFunctionExpression $ = ast.newArrowFunctionExpression();
if(tree.functionBody.type == ParseTreeType.BLOCK){
transformAndSetProperty($,ArrowFunctionExpression.BODY_PROPERTY,tree.functionBody);
}else{
transformAndSetProperty($,ArrowFunctionExpression.EXPRESSION_PROPERTY,tree.functionBody);
}
if(tree.formalParameterList != null ){
for(ParseTree param : tree.formalParameterList.parameters){
$.parameters().add(transform(ArrowFunctionExpression.PARAMETERS_PROPERTY,param));
}
}
return $;
}
FunctionDeclaration $ = ast.newFunctionDeclaration();
attachJSDoc(tree,$);
$.setGenerator(tree.isGenerator);
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY,tree.functionBody);
transformAndSetProperty($, FunctionDeclaration.RETURN_TYPE2_PROPERTY,tree.returnType);
if(tree.name != null ){
SimpleName name = transformLabelName(tree.name);
$.setMethodName(name);
$.setConstructor(name.getIdentifier().equals("constructor") || name.getIdentifier().equals("\"constructor\"")); //$NON-NLS-1$//$NON-NLS-2$
setSourceRange($, tree.name);
} else {
setSourceRange($, tree.formalParameterList);
}
if(tree.isStatic)
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
for(ParseTree param : tree.formalParameterList.parameters){
$.parameters().add(transform(FunctionDeclaration.PARAMETERS_PROPERTY,param));
}
if(tree.access != null){
ModifierKeyword modifierKeyword = null;
switch (tree.access) {
case PUBLIC:
modifierKeyword = ModifierKeyword.PUBLIC_KEYWORD;
break;
case PROTECTED:
modifierKeyword = ModifierKeyword.PROTECTED_KEYWORD;
break;
case PRIVATE:
modifierKeyword = ModifierKeyword.PRIVATE_KEYWORD;
break;
default :
throw new IllegalStateException("Unexpected access modifier type"); //$NON-NLS-1$
}
if(modifierKeyword != null){
$.modifiers().add(ast.newModifier(modifierKeyword));
}
}
return adjustFunctionDeclarationToProperty(property, $);
}
private ASTNode adjustFunctionDeclarationToProperty(final StructuralPropertyDescriptor property, final FunctionDeclaration declaration) {
Class<?> claz = classForProperty(property);
//test and return FunctionDeclaration first
if(claz.isAssignableFrom(FunctionDeclaration.class)){
return declaration;
}
if(claz.isAssignableFrom(Expression.class)){
FunctionExpression e = ast.newFunctionExpression();
e.setMethod(declaration);
return e;
}
if(claz.isAssignableFrom(Statement.class)){
return ast.newFunctionDeclarationStatement(declaration);
}
return declaration;
}
/**
* @param asCallExpression
* @return
*/
private ASTNode processFunctionCall(CallExpressionTree tree) {
FunctionInvocation $ = ast.newFunctionInvocation();
if(tree.operand.type == ParseTreeType.IDENTIFIER_EXPRESSION){
transformAndSetProperty($,FunctionInvocation.NAME_PROPERTY,tree.operand);
}else{
transformAndSetProperty($,FunctionInvocation.EXPRESSION_PROPERTY,tree.operand);
}
for (ParseTree pt : tree.arguments.arguments) {
$.arguments().add(transform(FunctionInvocation.ARGUMENTS_PROPERTY, pt));
}
return $;
}
/**
* @param asGetAccessor
* @return
*/
private ASTNode processGetAccessor(StructuralPropertyDescriptor property, GetAccessorTree tree) {
FunctionDeclaration $ = ast.newFunctionDeclaration();
$.setMethodName(transformObjectLitKeyAsString(tree.propertyName));
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY,tree.body);
$.modifiers().add(ast.newModifier(ModifierKeyword.GET_KEYWORD));
if(tree.isStatic){
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
}
return adjustFunctionDeclarationToProperty(property, $);
}
/**
* @param asIfStatement
* @return
*/
private ASTNode processIfStatement(IfStatementTree tree) {
IfStatement $ = ast.newIfStatement();
transformAndSetProperty($,IfStatement.EXPRESSION_PROPERTY,tree.condition);
transformAndSetProperty($,IfStatement.THEN_STATEMENT_PROPERTY,tree.ifClause);
transformAndSetProperty($, IfStatement.ELSE_STATEMENT_PROPERTY,tree.elseClause);
return $;
}
private ASTNode processIllegalToken(ParseTree node) {
System.out.println( "Unsupported syntax: " + node.type +" at "+ node.location.start.line +1); //$NON-NLS-1$//$NON-NLS-2$
return ast.newEmptyStatement();
}
/**
* @param asImportDeclaration
* @return
*/
private ASTNode processImportDecl(ImportDeclarationTree tree) {
ImportDeclaration $ = ast.newImportDeclaration();
if(tree.moduleSpecifier != null)
$.setSource(transformStringLiteral(tree.moduleSpecifier.asLiteral()));
if(tree.defaultBindingIdentifier != null){
ModuleSpecifier defaultModule = ast.newModuleSpecifier();
defaultModule.setDefault(true);
defaultModule.setLocal(transformLabelName(tree.defaultBindingIdentifier));
setSourceRange(defaultModule,tree.defaultBindingIdentifier);
$.specifiers().add(defaultModule);
}
if(tree.nameSpaceImportIdentifier != null ){
ModuleSpecifier m = ast.newModuleSpecifier();
m.setNamespace(true);
m.setLocal(transformLabelName(tree.nameSpaceImportIdentifier.asIdentifier()));
setSourceRange(m,tree.nameSpaceImportIdentifier);
$.specifiers().add(m);
}else if(tree.importSpecifierList != null){
for(ParseTree spec : tree.importSpecifierList){
$.specifiers().add(transform(ImportDeclaration.SPECIFIERS_PROPERTY,spec));
}
}
return $;
}
/**
* @param asImportSpecifier
* @return
*/
private ASTNode processImportSpec(ImportSpecifierTree tree) {
ModuleSpecifier $ = ast.newModuleSpecifier();
if(tree.destinationName != null)
$.setLocal(transformLabelName(tree.destinationName.asIdentifier()));
$.setDiscoverableName(transformLabelName(tree.importedName.asIdentifier()));
return $;
}
/**
* @param asLabelledStatement
* @return
*/
private ASTNode processLabeledStatement(LabelledStatementTree tree) {
LabeledStatement $ = ast.newLabeledStatement();
$.setLabel(transformLabelName(tree.name));
transformAndSetProperty($,LabeledStatement.BODY_PROPERTY,tree.statement);
return $;
}
/**
* @param asLiteralExpression
* @return
*/
private ASTNode processLiteralExpression(LiteralExpressionTree tree) {
switch (tree.literalToken.type) {
case NUMBER :
return transformNumberLiteral(tree.literalToken);
case STRING:
return transformStringLiteral(tree.literalToken);
case FALSE:
case TRUE:
return transformBooleanLiteral(tree.literalToken);
case NULL:
return transformNullLiteral(tree.literalToken);
case REGULAR_EXPRESSION:
return transformRegExpLiteral(tree.literalToken);
default :
throw new IllegalStateException("Unexpected literal type: " //$NON-NLS-1$
+ tree.literalToken.getClass() + " type: " //$NON-NLS-1$
+ tree.literalToken.type);
}
}
/**
* @param asModuleImport
* @return
*/
private ASTNode processModuleImport(ModuleImportTree tree) {
ImportDeclaration $ = ast.newImportDeclaration();
ModuleSpecifier m = ast.newModuleSpecifier();
if(tree.name != null)
m.setLocal(transformLabelName(tree.name));
m.setDiscoverableName(transformLabelName(tree.from.asIdentifier()));
m.setNamespace(true);
$.specifiers().add(m);
return $;
}
/**
* @param asIdentifierExpression
* @return
*/
private ASTNode processName(StructuralPropertyDescriptor property, IdentifierExpressionTree tree) {
Class<?> claz = classForProperty(property);
if(tree.identifierToken == null){
return null;
}
SimpleName sn = transformLabelName(tree.identifierToken);
if(claz.isAssignableFrom(SingleVariableDeclaration.class)){
SingleVariableDeclaration $ = ast.newSingleVariableDeclaration();
$.setName(sn);
return $;
}
return sn;
}
/**
* @param asNewExpression
* @return
*/
private ASTNode processNewExpression(NewExpressionTree tree) {
ClassInstanceCreation $ = ast.newClassInstanceCreation();
transformAndSetProperty($,ClassInstanceCreation.MEMBER_PROPERTY,tree.operand);
if(tree.arguments != null ){
for(ParseTree arg : tree.arguments.arguments){
$.arguments().add(transform(ClassInstanceCreation.ARGUMENTS_PROPERTY,arg));
}
}
return $;
}
/**
* @param asNull
* @return
*/
private ASTNode processNull(NullTree tree) {
return ast.newEmptyStatement();
}
/**
* @param asObjectPattern
* @return
*/
private ASTNode processObjectPattern(StructuralPropertyDescriptor property, ObjectPatternTree tree) {
ObjectName $ = ast.newObjectName();
for(ParseTree child: tree.fields){
$.objectProperties().add(convertToObjectLiteralField(child));
}
if(classForProperty(property).isAssignableFrom(SingleVariableDeclaration.class)){
SingleVariableDeclaration svd = ast.newSingleVariableDeclaration();
svd.setPattern($);
return svd;
}
return $;
}
/**
* @param asObjectLiteralExpression
* @return
*/
private ASTNode processObjectLiteral(ObjectLiteralExpressionTree tree) {
ObjectLiteral $ = ast.newObjectLiteral();
for(ParseTree elem : tree.propertyNameAndValues){
ObjectLiteralField f = convertToObjectLiteralField(elem);
$.fields().add(f);
}
return $;
}
/**
* @param elem
* @return
*/
private ObjectLiteralField convertToObjectLiteralField(ParseTree elem) {
ObjectLiteralField f = ast.newObjectLiteralField();
switch (elem.type) {
case GET_ACCESSOR:{
f.setKind(FieldKind.GET);
final GetAccessorTree getAccessor = elem.asGetAccessor();
f.setFieldName(transformObjectLitKeyAsString(getAccessor.propertyName));
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,getAccessor);
break;
}
case COMPUTED_PROPERTY_GETTER:{
f.setKind(FieldKind.GET);
final ComputedPropertyGetterTree compGetter= elem.asComputedPropertyGetter();
transformAndSetProperty(f,ObjectLiteralField.FIELD_NAME_PROPERTY,compGetter.property);
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,compGetter);
break;
}
case SET_ACCESSOR:{
f.setKind(FieldKind.SET);
final SetAccessorTree setAccessor= elem.asSetAccessor();
f.setFieldName(transformObjectLitKeyAsString(setAccessor.propertyName));
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,setAccessor);
break;
}
case COMPUTED_PROPERTY_SETTER:{
f.setKind(FieldKind.SET);
final ComputedPropertySetterTree compSetter = elem.asComputedPropertySetter();
transformAndSetProperty(f, ObjectLiteralField.FIELD_NAME_PROPERTY,compSetter.property);
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,compSetter.body);
break;
}
case COMPUTED_PROPERTY_DEFINITION:{
f.setKind(FieldKind.INIT);
final ComputedPropertyDefinitionTree compDef = elem.asComputedPropertyDefinition();
transformAndSetProperty(f, ObjectLiteralField.FIELD_NAME_PROPERTY,compDef.property);
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY, compDef.value);
break;
}
case COMPUTED_PROPERTY_MEMBER_VARIABLE:{
f.setKind(FieldKind.INIT);
final ComputedPropertyMemberVariableTree compVariable = elem.asComputedPropertyMemberVariable();
transformAndSetProperty(f, ObjectLiteralField.FIELD_NAME_PROPERTY, compVariable.property);
transformAndSetProperty(f, ObjectLiteralField.INITIALIZER_PROPERTY, compVariable.declaredType);
break;
}
case COMPUTED_PROPERTY_METHOD:{
f.setKind(FieldKind.INIT);
final ComputedPropertyMethodTree compMethod = elem.asComputedPropertyMethod();
transformAndSetProperty(f,ObjectLiteralField.FIELD_NAME_PROPERTY,compMethod.property);
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,compMethod);
break;
}
case FUNCTION_DECLARATION:{
f.setKind(FieldKind.INIT);
final FunctionDeclarationTree functionDeclaration = elem.asFunctionDeclaration();
f.setFieldName(transformObjectLitKeyAsString(functionDeclaration.name));
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,functionDeclaration);
break;
}
case DEFAULT_PARAMETER:{
f.setKind(FieldKind.INIT);
final DefaultParameterTree defaultTree = elem.asDefaultParameter();
transformAndSetProperty(f,ObjectLiteralField.FIELD_NAME_PROPERTY,defaultTree.lhs);
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,defaultTree.defaultValue);
break;
}
default :{
f.setKind(FieldKind.INIT);
final PropertyNameAssignmentTree assignment = elem.asPropertyNameAssignment();
f.setFieldName(transformObjectLitKeyAsString(assignment.name));
transformAndSetProperty(f,ObjectLiteralField.INITIALIZER_PROPERTY,assignment.value);
break;
}
}
setSourceRange(f,elem);
return f;
}
/**
* @param asParenExpression
* @return
*/
private ASTNode processParenthesizedExpression(ParenExpressionTree tree) {
ParenthesizedExpression $ = ast.newParenthesizedExpression();
transformAndSetProperty($, ParenthesizedExpression.EXPRESSION_PROPERTY,tree.expression);
return $;
}
/**
* @param asPostfixExpression
* @return
*/
private ASTNode processPostfixExpression(PostfixExpressionTree tree) {
PostfixExpression $ = ast.newPostfixExpression();
transformAndSetProperty($,PostfixExpression.OPERAND_PROPERTY,tree.operand);
$.setOperator(PostfixExpression.Operator.toOperator(tree.operator.toString()));
return $;
}
/**
* @param asMemberExpression
* @return
*/
private ASTNode processPropertyGet(StructuralPropertyDescriptor property, MemberExpressionTree tree) {
SimpleName name = null;
if(tree.memberName != null)
name = transformLabelName(tree.memberName);
if(tree.operand == null && classForProperty(property) == SimpleName.class)
return name;
FieldAccess $ = ast.newFieldAccess();
if(name != null){
$.setName(name);
}
transformAndSetProperty($,FieldAccess.EXPRESSION_PROPERTY,tree.operand);
return $;
}
/**
* @param asPropertyNameAssignment
* @return
*/
private ASTNode processPropertyNameAssignment(PropertyNameAssignmentTree tree) {
VariableDeclarationFragment vdf = ast.newVariableDeclarationFragment();
if(tree.name != null)
vdf.setName(transformLabelName((IdentifierToken) tree.name));
transformAndSetProperty(vdf,VariableDeclarationFragment.INITIALIZER_PROPERTY,tree.value);
return ast.newFieldDeclaration(vdf);
}
/**
* @param asRestParameter
* @return
*/
private ASTNode processRestParameter(StructuralPropertyDescriptor property, RestParameterTree tree) {
RestElementName rest = null;
if(tree.identifier != null){
rest = ast.newRestElementName();
rest.setArgument(transformLabelName(tree.identifier));
}
if(classForProperty(property).isAssignableFrom(SingleVariableDeclaration.class)){
SingleVariableDeclaration $ = ast.newSingleVariableDeclaration();
if(rest !=null)
$.setPattern(rest);
$.setVarargs(true);
return $;
}
return rest;
}
/**
* @param asReturnStatement
* @return
*/
private ASTNode processReturnStatement(ReturnStatementTree tree ) {
ReturnStatement $ = ast.newReturnStatement();
transformAndSetProperty($,ReturnStatement.EXPRESSION_PROPERTY, tree.expression);
return $;
}
/**
* @param asSetAccessor
* @return
*/
private ASTNode processSetAccessor(StructuralPropertyDescriptor property, SetAccessorTree tree) {
FunctionDeclaration $ = ast.newFunctionDeclaration();
$.modifiers().add(ast.newModifier(ModifierKeyword.SET_KEYWORD));
$.setMethodName(transformObjectLitKeyAsString(tree.propertyName));
transformAndSetProperty($,FunctionDeclaration.BODY_PROPERTY,tree.body);
final SingleVariableDeclaration p = ast.newSingleVariableDeclaration();
if(tree.parameter != null)
p.setName(transformLabelName(tree.parameter));
$.parameters().add(p);
if(tree.isStatic){
$.modifiers().add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
}
return adjustFunctionDeclarationToProperty(property,$);
}
/**
* @param asSpreadExpression
* @return
*/
private ASTNode processSpreadExpression(SpreadExpressionTree tree) {
SpreadElement $ = ast.newSpreadElement();
transformAndSetProperty($, SpreadElement.ARGUMENT_PROPERTY,tree.expression);
return $;
}
/**
* @param asSuperExpression
* @return
*/
private ASTNode processSuper(SuperExpressionTree tree) {
//FIXME: we need a better way to handle super references. Simply
// treating as a name is not enough.
return ast.newSimpleName(KEYWORD_SUPER);
}
/**
* @param asCaseClause
* @return
*/
private ASTNode processSwitchCase(CaseClauseTree tree) {
// statements of CaseClauseTree are handled on processSwitchStatement()
SwitchCase $ = ast.newSwitchCase();
transformAndSetProperty($, SwitchCase.EXPRESSION_PROPERTY,tree.expression);
return $;
}
/**
* @param asDefaultClause
* @return
*/
private ASTNode processSwitchDefault(DefaultClauseTree tree) {
// statements of DefaultClauseTree are handled on processSwitchStatement()
SwitchCase $ = ast.newSwitchCase();
$.setExpression(null);
return $;
}
/**
* @param asSwitchStatement
* @return
*/
private ASTNode processSwitchStatement(SwitchStatementTree tree) {
SwitchStatement $ = ast.newSwitchStatement();
transformAndSetProperty($,SwitchStatement.EXPRESSION_PROPERTY,tree.expression);
for (ParseTree pt : tree.caseClauses) {
if(pt.type == ParseTreeType.DEFAULT_CLAUSE){
DefaultClauseTree dct = pt.asDefaultClause();
$.statements().add(transform(SwitchStatement.STATEMENTS_PROPERTY,dct));
for (ParseTree dcs : dct.statements) {
$.statements().add(transform(SwitchStatement.STATEMENTS_PROPERTY, dcs));
}
}else{
CaseClauseTree cct = pt.asCaseClause();
$.statements().add(transform(SwitchStatement.STATEMENTS_PROPERTY,cct));
for(ParseTree ccs : cct.statements){
$.statements().add(transform(SwitchStatement.STATEMENTS_PROPERTY,ccs));
}
}
}
return $;
}
/**
* @param asTemplateLiteralExpression
* @return
*/
private ASTNode processTemplateLiteral(TemplateLiteralExpressionTree tree) {
TemplateLiteral $ = ast.newTemplateLiteral();
transformAndSetProperty($,TemplateLiteral.TAG_PROPERTY,tree.operand);
Iterator<ParseTree> iterator = tree.elements.iterator();
ParseTree pt = null;
while(iterator.hasNext()){
pt = iterator.next();
if(pt.type == ParseTreeType.TEMPLATE_LITERAL_PORTION){
final TemplateElement element = (TemplateElement) transform(TemplateLiteral.ELEMENTS_PROPERTY,pt);
element.setTail(!iterator.hasNext());
$.elements().add(element);
}
else{
$.expressions().add(transform(TemplateLiteral.EXPRESSIONS_PROPERTY,pt));
}
}
//Add a tail element if there is not one.
if(pt != null && pt.type != ParseTreeType.TEMPLATE_LITERAL_PORTION){
TemplateElement el = ast.newTemplateElement();
el.setSourceRange(pt.location.start.offset,0);
el.setTail(true);
$.elements().add(el);
}
return $;
}
/**
* @param asTemplateLiteralPortion
* @return
*/
private ASTNode processTemplateLiteralPortion(TemplateLiteralPortionTree tree) {
TemplateElement $ = ast.newTemplateElement();
safeSetProperty($,TemplateElement.RAW_VALUE_PROPERTY,tree.value.asLiteral().value);
return $;
}
/**
* @param asTemplateSubstitution
* @return
*/
private ASTNode processTemplateSubstitution(TemplateSubstitutionTree tree) {
return transform(TemplateLiteral.EXPRESSIONS_PROPERTY,tree.expression);
}
/**
* @param asThisExpression
* @return
*/
private ASTNode processThisExpression(ThisExpressionTree tree) {
return ast.newThisExpression();
}
/**
* @param asThrowStatement
* @return
*/
private ASTNode processThrowStatement(ThrowStatementTree tree) {
ThrowStatement $ = ast.newThrowStatement();
transformAndSetProperty($, ThrowStatement.EXPRESSION_PROPERTY,tree.value);
return $;
}
/**
* @param asTryStatement
* @return
*/
private ASTNode processTryStatement(TryStatementTree tree) {
TryStatement $ = ast.newTryStatement();
transformAndSetProperty($,TryStatement.BODY_PROPERTY,tree.body);
if(tree.catchBlock != null ){
$.catchClauses().add(transform(TryStatement.CATCH_CLAUSES_PROPERTY,tree.catchBlock));
}
transformAndSetProperty($,TryStatement.FINALLY_PROPERTY,tree.finallyBlock);
return $;
}
/**
* @param asTypeName
* @return
*/
private ASTNode processTypeName(TypeNameTree tree) {
Name $ = null;
Iterator<String> segmentsIt = tree.segments.iterator();
while(segmentsIt.hasNext()){
SimpleName n = ast.newSimpleName(segmentsIt.next());
if($ == null ){
$ = n;
}else{
$ = ast.newQualifiedName($,n);
}
}
return $;
}
/**
* @param asUnaryExpression
* @return
*/
private ASTNode processUnaryExpression(UnaryExpressionTree tree) {
PrefixExpression $ = ast.newPrefixExpression();
$.setOperator(PrefixExpression.Operator.toOperator(tree.operator.toString()));
transformAndSetProperty($,PrefixExpression.OPERAND_PROPERTY,tree.operand);
return $;
}
/**
* @param asVariableDeclaration
* @return
*/
private ASTNode processVariableDeclaration(VariableDeclarationTree tree) {
VariableDeclarationFragment $ = ast.newVariableDeclarationFragment();
//TODO: Handle destructuring assignment
transformAndSetProperty($,VariableDeclarationFragment.PATTERN_PROPERTY,tree.lvalue);
transformAndSetProperty($,VariableDeclarationFragment.INITIALIZER_PROPERTY,tree.initializer);
return $;
}
/**
* @param asVariableDeclarationList
* @return
*/
private ASTNode processVariableDeclarationList(VariableDeclarationListTree tree) {
// Only trees with single elements are handled here
// multiple elements should be handled on their caller
// process* methods
VariableDeclarationExpression $ = ast.newVariableDeclarationExpression((VariableDeclarationFragment) transform(VariableDeclarationExpression.FRAGMENTS_PROPERTY,tree.declarations.get(0)));
$.setKind(convertVariableKind(tree.declarationType));
return $;
}
/**
* @param asVariableStatement
* @return
*/
private ASTNode processVariableStatement(VariableStatementTree tree) {
VariableDeclarationStatement $ = ast.newVariableDeclarationStatement();
switch (tree.declarations.declarationType) {
case CONST :
$.setKind(VariableKind.CONST);
break;
case LET:
$.setKind(VariableKind.LET);
break;
default :
$.setKind(VariableKind.VAR);
break;
}
for(ParseTree decl : tree.declarations.declarations){
$.fragments().add(transform(VariableDeclarationStatement.FRAGMENTS_PROPERTY,decl));
}
attachJSDoc(tree,$);
return $;
}
/**
* @param asWhileStatement
* @return
*/
private ASTNode processWhileLoop(WhileStatementTree tree) {
WhileStatement $ = ast.newWhileStatement();
transformAndSetProperty($, WhileStatement.EXPRESSION_PROPERTY, tree.condition);
transformAndSetProperty($, WhileStatement.BODY_PROPERTY, tree.body);
return $;
}
/**
* @param asWithStatement
* @return
*/
private ASTNode processWithStatement(WithStatementTree tree) {
WithStatement $ = ast.newWithStatement();
transformAndSetProperty($,WithStatement.BODY_PROPERTY,tree.body);
transformAndSetProperty($,WithStatement.EXPRESSION_PROPERTY,tree.expression);
return $;
}
/**
* @param asYieldStatement
* @return
*/
private ASTNode processYield(YieldExpressionTree tree) {
YieldExpression $ = ast.newYieldExpression();
$.setDelegate(Boolean.valueOf(tree.isYieldFor));
transformAndSetProperty($,YieldExpression.ARGUMENT_PROPERTY,tree.expression);
return $;
}
/**
* @param node
* @param tree
*/
private void setSourceRange(ASTNode node, ParseTree tree) {
int startOffset = tree.location.start.offset;
if(node instanceof BodyDeclaration ){
BodyDeclaration bd = (BodyDeclaration)node;
if(bd.getJavadoc() != null ){
startOffset = bd.getJavadoc().getStartPosition();
}
}else if(node.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT){
VariableDeclarationStatement vs = (VariableDeclarationStatement)node;
if(vs.getJavadoc() != null){
startOffset = vs.getJavadoc().getStartPosition();
}
}
node.setSourceRange(startOffset, Math.max(tree.location.end.offset - startOffset, 0));
}
/**
* @param node
* @param tree
*/
private void setSourceRange(ASTNode node, Token token) {
node.setSourceRange(token.location.start.offset, token.location.end.offset - token.location.start.offset);
}
private Comment handleJsDoc(ParseTree node) {
if (!shouldAttachJSDocHere(node)) {
return null;
}
return getJsDoc(node.location);
}
private boolean shouldAttachJSDocHere(ParseTree tree) {
switch (tree.type) {
case EXPRESSION_STATEMENT:
case LABELLED_STATEMENT:
case EXPORT_DECLARATION:
return false;
case CALL_EXPRESSION:
case CONDITIONAL_EXPRESSION:
case BINARY_OPERATOR:
case MEMBER_EXPRESSION:
case MEMBER_LOOKUP_EXPRESSION:
case POSTFIX_EXPRESSION:
ParseTree nearest = findNearestNode(tree);
if (nearest.type == ParseTreeType.PAREN_EXPRESSION) {
return false;
}
return true;
default:
return true;
}
}
private Comment getJsDoc(SourceRange location) {
Comment closestPreviousComment = null;
while (currentComment != null &&
currentComment.location.end.offset <= location.start.offset) {
if (currentComment.type == Comment.Type.JSDOC) {
closestPreviousComment = currentComment;
}
if (this.nextCommentIter.hasNext()) {
currentComment = this.nextCommentIter.next();
} else {
currentComment = null;
}
}
return closestPreviousComment;
}
private static ParseTree findNearestNode(ParseTree tree) {
while (true) {
switch (tree.type) {
case EXPRESSION_STATEMENT:
tree = tree.asExpressionStatement().expression;
continue;
case CALL_EXPRESSION:
tree = tree.asCallExpression().operand;
continue;
case BINARY_OPERATOR:
tree = tree.asBinaryOperator().left;
continue;
case CONDITIONAL_EXPRESSION:
tree = tree.asConditionalExpression().condition;
continue;
case MEMBER_EXPRESSION:
tree = tree.asMemberExpression().operand;
continue;
case MEMBER_LOOKUP_EXPRESSION:
tree = tree.asMemberLookupExpression().operand;
continue;
case POSTFIX_EXPRESSION:
tree = tree.asPostfixExpression().operand;
continue;
default:
return tree;
}
}
}
private ASTNode transformBooleanLiteral(Token token) {
BooleanLiteral $ = ast.newBooleanLiteral(token.type == TokenType.TRUE);
setSourceRange($,token);
return $;
}
private SimpleName transformLabelName(IdentifierToken token) {
SimpleName $ = ast.newSimpleName(token.value);
setSourceRange($, token);
return $;
}
private ASTNode transformNullLiteral(Token token) {
NullLiteral $ = ast.newNullLiteral();
setSourceRange($,token);
return $;
}
private ASTNode transformNumberLiteral(Token token) {
NumberLiteral $ = ast.newNumberLiteral();
$.internalSetToken(token.asLiteral().value);
setSourceRange($, token);
return $;
}
private SimpleName transformObjectLitKeyAsString(com.google.javascript.jscomp.parsing.parser.Token token) {
SimpleName $ = null;
if (token == null) {
$ = ast.newSimpleName(""); //$NON-NLS-1$
setSourceRange($, token);
}
else if (token.type == TokenType.IDENTIFIER) {
$ = transformLabelName(token.asIdentifier());
}
else {// literal or number
$ = ast.newSimpleName(token.asLiteral().value);
setSourceRange($, token);
}
return $;
}
private ASTNode transformRegExpLiteral(Token token) {
RegularExpressionLiteral $ = ast.newRegularExpressionLiteral();
$.internalSetRegularExpression(token.asLiteral().value);
setSourceRange($,token);
return $;
}
private StringLiteral transformStringLiteral(Token token) {
StringLiteral $ = ast.newStringLiteral();
$.internalSetEscapedValue(token.asLiteral().value);
setSourceRange($,token);
return $;
}
private void transformAndSetProperty(ASTNode node, StructuralPropertyDescriptor property, ParseTree tree){
if(tree == null ) return;
safeSetProperty(node, property, transform(property, tree));
}
private void safeSetProperty(ASTNode node, StructuralPropertyDescriptor property, Object value){
if(property.isChildProperty()){
ChildPropertyDescriptor cp = (ChildPropertyDescriptor)property;
if(cp.isMandatory() && value == null ){
return;
}
}
node.setStructuralProperty(property, value);
}
/**
* @param property
*/
private Class<?> classForProperty(StructuralPropertyDescriptor property) {
if(property.isChildProperty()){
ChildPropertyDescriptor cp = (ChildPropertyDescriptor)property;
return cp.getChildType();
}
if (property.isChildListProperty() ){
ChildListPropertyDescriptor cl = (ChildListPropertyDescriptor) property;
return cl.getElementType();
}
if(property.isSimpleProperty()){
SimplePropertyDescriptor sp = (SimplePropertyDescriptor) property;
sp.getValueType();
}
return Object.class;
}
}