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