EcmascriptTreeBuilder.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.ecmascript.ast;
005 
006 import java.lang.reflect.Constructor;
007 import java.lang.reflect.InvocationTargetException;
008 import java.util.HashMap;
009 import java.util.Map;
010 import java.util.Stack;
011 
012 import net.sourceforge.pmd.lang.ast.Node;
013 
014 import org.mozilla.javascript.ast.ArrayComprehension;
015 import org.mozilla.javascript.ast.ArrayComprehensionLoop;
016 import org.mozilla.javascript.ast.ArrayLiteral;
017 import org.mozilla.javascript.ast.Assignment;
018 import org.mozilla.javascript.ast.AstNode;
019 import org.mozilla.javascript.ast.AstRoot;
020 import org.mozilla.javascript.ast.Block;
021 import org.mozilla.javascript.ast.BreakStatement;
022 import org.mozilla.javascript.ast.CatchClause;
023 import org.mozilla.javascript.ast.Comment;
024 import org.mozilla.javascript.ast.ConditionalExpression;
025 import org.mozilla.javascript.ast.ContinueStatement;
026 import org.mozilla.javascript.ast.DoLoop;
027 import org.mozilla.javascript.ast.ElementGet;
028 import org.mozilla.javascript.ast.EmptyExpression;
029 import org.mozilla.javascript.ast.ExpressionStatement;
030 import org.mozilla.javascript.ast.ForInLoop;
031 import org.mozilla.javascript.ast.ForLoop;
032 import org.mozilla.javascript.ast.FunctionCall;
033 import org.mozilla.javascript.ast.FunctionNode;
034 import org.mozilla.javascript.ast.IfStatement;
035 import org.mozilla.javascript.ast.InfixExpression;
036 import org.mozilla.javascript.ast.KeywordLiteral;
037 import org.mozilla.javascript.ast.Label;
038 import org.mozilla.javascript.ast.LabeledStatement;
039 import org.mozilla.javascript.ast.LetNode;
040 import org.mozilla.javascript.ast.Name;
041 import org.mozilla.javascript.ast.NewExpression;
042 import org.mozilla.javascript.ast.NodeVisitor;
043 import org.mozilla.javascript.ast.NumberLiteral;
044 import org.mozilla.javascript.ast.ObjectLiteral;
045 import org.mozilla.javascript.ast.ObjectProperty;
046 import org.mozilla.javascript.ast.ParenthesizedExpression;
047 import org.mozilla.javascript.ast.PropertyGet;
048 import org.mozilla.javascript.ast.RegExpLiteral;
049 import org.mozilla.javascript.ast.ReturnStatement;
050 import org.mozilla.javascript.ast.Scope;
051 import org.mozilla.javascript.ast.StringLiteral;
052 import org.mozilla.javascript.ast.SwitchCase;
053 import org.mozilla.javascript.ast.SwitchStatement;
054 import org.mozilla.javascript.ast.ThrowStatement;
055 import org.mozilla.javascript.ast.TryStatement;
056 import org.mozilla.javascript.ast.UnaryExpression;
057 import org.mozilla.javascript.ast.VariableDeclaration;
058 import org.mozilla.javascript.ast.VariableInitializer;
059 import org.mozilla.javascript.ast.WhileLoop;
060 import org.mozilla.javascript.ast.WithStatement;
061 import org.mozilla.javascript.ast.XmlDotQuery;
062 import org.mozilla.javascript.ast.XmlExpression;
063 import org.mozilla.javascript.ast.XmlMemberGet;
064 import org.mozilla.javascript.ast.XmlString;
065 
066 public class EcmascriptTreeBuilder implements NodeVisitor {
067 
068     protected static final Map<Class<? extends AstNode>, Constructor<? extends EcmascriptNode>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<Class<? extends AstNode>, Constructor<? extends EcmascriptNode>>();
069     static {
070   register(ArrayComprehension.class, ASTArrayComprehension.class);
071   register(ArrayComprehensionLoop.class, ASTArrayComprehensionLoop.class);
072   register(ArrayLiteral.class, ASTArrayLiteral.class);
073   register(Assignment.class, ASTAssignment.class);
074   register(AstRoot.class, ASTAstRoot.class);
075   register(Block.class, ASTBlock.class);
076   register(BreakStatement.class, ASTBreakStatement.class);
077   register(CatchClause.class, ASTCatchClause.class);
078   register(Comment.class, ASTComment.class);
079   register(ConditionalExpression.class, ASTConditionalExpression.class);
080   register(ContinueStatement.class, ASTContinueStatement.class);
081   register(DoLoop.class, ASTDoLoop.class);
082   register(ElementGet.class, ASTElementGet.class);
083   register(EmptyExpression.class, ASTEmptyExpression.class);
084   register(ExpressionStatement.class, ASTExpressionStatement.class);
085   register(ForInLoop.class, ASTForInLoop.class);
086   register(ForLoop.class, ASTForLoop.class);
087   register(FunctionCall.class, ASTFunctionCall.class);
088   register(FunctionNode.class, ASTFunctionNode.class);
089   register(IfStatement.class, ASTIfStatement.class);
090   register(InfixExpression.class, ASTInfixExpression.class);
091   register(KeywordLiteral.class, ASTKeywordLiteral.class);
092   register(Label.class, ASTLabel.class);
093   register(LabeledStatement.class, ASTLabeledStatement.class);
094   register(LetNode.class, ASTLetNode.class);
095   register(Name.class, ASTName.class);
096   register(NewExpression.class, ASTNewExpression.class);
097   register(NumberLiteral.class, ASTNumberLiteral.class);
098   register(ObjectLiteral.class, ASTObjectLiteral.class);
099   register(ObjectProperty.class, ASTObjectProperty.class);
100   register(ParenthesizedExpression.class, ASTParenthesizedExpression.class);
101   register(PropertyGet.class, ASTPropertyGet.class);
102   register(RegExpLiteral.class, ASTRegExpLiteral.class);
103   register(ReturnStatement.class, ASTReturnStatement.class);
104   register(Scope.class, ASTScope.class);
105   register(StringLiteral.class, ASTStringLiteral.class);
106   register(SwitchCase.class, ASTSwitchCase.class);
107   register(SwitchStatement.class, ASTSwitchStatement.class);
108   register(ThrowStatement.class, ASTThrowStatement.class);
109   register(TryStatement.class, ASTTryStatement.class);
110   register(UnaryExpression.class, ASTUnaryExpression.class);
111   register(VariableDeclaration.class, ASTVariableDeclaration.class);
112   register(VariableInitializer.class, ASTVariableInitializer.class);
113   register(WhileLoop.class, ASTWhileLoop.class);
114   register(WithStatement.class, ASTWithStatement.class);
115   register(XmlDotQuery.class, ASTXmlDotQuery.class);
116   register(XmlExpression.class, ASTXmlExpression.class);
117   register(XmlMemberGet.class, ASTXmlMemberGet.class);
118   register(XmlString.class, ASTXmlString.class);
119     }
120 
121     protected static void register(Class<? extends AstNode> nodeType, Class<? extends EcmascriptNode> nodeAdapterType) {
122   try {
123       NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType));
124   catch (SecurityException e) {
125       throw new RuntimeException(e);
126   catch (NoSuchMethodException e) {
127       throw new RuntimeException(e);
128   }
129     }
130 
131     // The nodes having children built.
132     protected Stack<Node> nodes = new Stack<Node>();
133 
134     // The Rhino nodes with children to build.
135     protected Stack<AstNode> parents = new Stack<AstNode>();
136 
137     protected EcmascriptNode createNodeAdapter(AstNode node) {
138   try {
139       Constructor<? extends EcmascriptNode> constructor = NODE_TYPE_TO_NODE_ADAPTER_TYPE.get(node.getClass());
140       if (constructor == null) {
141     throw new IllegalArgumentException("There is no Node adapter class registered for the Node class: "
142       + node.getClass());
143       }
144       return constructor.newInstance(node);
145   catch (InstantiationException e) {
146       throw new RuntimeException(e);
147   catch (IllegalAccessException e) {
148       throw new RuntimeException(e);
149   catch (InvocationTargetException e) {
150       throw new RuntimeException(e.getTargetException());
151   }
152     }
153 
154     public EcmascriptNode build(AstNode astNode) {
155   // Create a Node
156   EcmascriptNode node = createNodeAdapter(astNode);
157 
158   // Append to parent
159   Node parent = nodes.isEmpty() null : nodes.peek();
160   if (parent != null) {
161       parent.jjtAddChild(node, parent.jjtGetNumChildren());
162       node.jjtSetParent(parent);
163   }
164 
165   // Build the children...
166   nodes.push(node);
167   parents.push(astNode);
168   astNode.visit(this);
169   nodes.pop();
170   parents.pop();
171 
172   return node;
173     }
174 
175     public boolean visit(AstNode node) {
176   if (parents.peek() == node) {
177       return true;
178   else {
179       build(node);
180       return false;
181   }
182     }
183 }