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 }
|