001: /* ====================================================================
002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
003: * ====================================================================
004: * The Tea Software License, Version 1.1
005: *
006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Walt Disney Internet Group (http://opensource.go.com/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact opensource@dig.com.
031: *
032: * 5. Products derived from this software may not be called "Tea",
033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
035: * written permission of the Walt Disney Internet Group.
036: *
037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048: * ====================================================================
049: *
050: * For more information about Tea, please see http://opensource.go.com/.
051: */
052:
053: package com.go.tea.parsetree;
054:
055: import java.util.Iterator;
056: import com.go.tea.compiler.Type;
057: import com.go.tea.compiler.SourceInfo;
058:
059: /******************************************************************************
060: * TreeMutator is similar to {@link TreeWalker TreeWalker} in that it
061: * traverses a parse tree in canonocal order, and only a few visit methods
062: * should be overridden. The key difference is that visit methods must
063: * return a node of the same type as the one passed in. By returning a node
064: * which isn't the same as the one passed in, a node can be replaced.
065: *
066: * @author Brian S O'Neill
067: * @version
068: * <!--$$Revision:--> 20 <!-- $-->, <!--$$JustDate:--> 5/31/01 <!-- $-->
069: */
070: public abstract class TreeMutator implements NodeVisitor {
071: public Object visit(Template node) {
072: node.getName().accept(this );
073:
074: Variable[] params = node.getParams();
075: if (params != null) {
076: for (int i = 0; i < params.length; i++) {
077: params[i] = (Variable) params[i].accept(this );
078: }
079: }
080:
081: Statement stmt = node.getStatement();
082: if (stmt != null) {
083: node.setStatement((Statement) stmt.accept(this ));
084: }
085:
086: return node;
087: }
088:
089: public Object visit(Name node) {
090: return node;
091: }
092:
093: public Object visit(TypeName node) {
094: return node;
095: }
096:
097: public Object visit(Variable node) {
098: node.getTypeName().accept(this );
099: return node;
100: }
101:
102: public Object visit(ExpressionList node) {
103: Expression[] exprs = node.getExpressions();
104: for (int i = 0; i < exprs.length; i++) {
105: exprs[i] = visitExpression(exprs[i]);
106: }
107:
108: return node;
109: }
110:
111: public Object visit(Statement node) {
112: return node;
113: }
114:
115: public Object visit(StatementList node) {
116: Statement[] stmts = node.getStatements();
117: if (stmts != null) {
118: for (int i = 0; i < stmts.length; i++) {
119: stmts[i] = (Statement) stmts[i].accept(this );
120: }
121: }
122:
123: return node;
124: }
125:
126: public Object visit(Block node) {
127: Statement init = node.getInitializer();
128: if (init != null) {
129: node.setInitializer((Statement) init.accept(this ));
130: }
131:
132: visit((StatementList) node);
133:
134: Statement fin = node.getFinalizer();
135: if (fin != null) {
136: node.setFinalizer((Statement) fin.accept(this ));
137: }
138:
139: return node;
140: }
141:
142: public Object visit(AssignmentStatement node) {
143: node.getLValue().accept(this );
144: node.setRValue(visitExpression(node.getRValue()));
145:
146: return node;
147: }
148:
149: public Object visit(BreakStatement node) {
150: return node;
151: }
152:
153: public Object visit(ForeachStatement node) {
154: node.getLoopVariable().accept(this );
155: node.setRange(visitExpression(node.getRange()));
156: Expression endRange = node.getEndRange();
157: if (endRange != null) {
158: node.setEndRange(visitExpression(endRange));
159: }
160:
161: Statement init = node.getInitializer();
162: if (init != null) {
163: node.setInitializer((Statement) init.accept(this ));
164: }
165:
166: Block body = node.getBody();
167: if (body != null) {
168: node.setBody(visitBlock(body));
169: }
170:
171: return node;
172: }
173:
174: public Object visit(IfStatement node) {
175: node.setCondition(visitExpression(node.getCondition()));
176:
177: Block block = node.getThenPart();
178: if (block != null) {
179: node.setThenPart(visitBlock(block));
180: }
181:
182: block = node.getElsePart();
183: if (block != null) {
184: node.setElsePart(visitBlock(block));
185: }
186:
187: return node;
188: }
189:
190: public Object visit(SubstitutionStatement node) {
191: return node;
192: }
193:
194: public Object visit(ExpressionStatement node) {
195: node.setExpression(visitExpression(node.getExpression()));
196: return node;
197: }
198:
199: public Object visit(ReturnStatement node) {
200: Expression expr = node.getExpression();
201: if (expr != null) {
202: node.setExpression(visitExpression(node.getExpression()));
203: }
204: return node;
205: }
206:
207: public Object visit(ExceptionGuardStatement node) {
208: node.setGuarded((Statement) node.getGuarded().accept(this ));
209: Statement stmt = node.getReplacement();
210: if (stmt != null) {
211: node.setReplacement((Statement) stmt.accept(this ));
212: }
213: return node;
214: }
215:
216: public Object visit(Expression node) {
217: return node;
218: }
219:
220: public Object visit(ParenExpression node) {
221: node.setExpression(visitExpression(node.getExpression()));
222: return node;
223: }
224:
225: public Object visit(NewArrayExpression node) {
226: node.setExpressionList((ExpressionList) node
227: .getExpressionList().accept(this ));
228: return node;
229: }
230:
231: public Object visit(FunctionCallExpression node) {
232: return visit((CallExpression) node);
233: }
234:
235: public Object visit(TemplateCallExpression node) {
236: return visit((CallExpression) node);
237: }
238:
239: private Object visit(CallExpression node) {
240: node.setParams((ExpressionList) node.getParams().accept(this ));
241:
242: Statement init = node.getInitializer();
243: if (init != null) {
244: node.setInitializer((Statement) init.accept(this ));
245: }
246:
247: Block subParam = node.getSubstitutionParam();
248: if (subParam != null) {
249: node.setSubstitutionParam(visitBlock(subParam));
250: }
251:
252: return node;
253: }
254:
255: public Object visit(VariableRef node) {
256: Variable v = node.getVariable();
257: if (v != null) {
258: node.setVariable((Variable) v.accept(this ));
259: }
260:
261: return node;
262: }
263:
264: public Object visit(Lookup node) {
265: node.setExpression(visitExpression(node.getExpression()));
266: return node;
267: }
268:
269: public Object visit(ArrayLookup node) {
270: node.setExpression(visitExpression(node.getExpression()));
271: node.setLookupIndex(visitExpression(node.getLookupIndex()));
272: return node;
273: }
274:
275: public Object visit(NegateExpression node) {
276: node.setExpression(visitExpression(node.getExpression()));
277: return node;
278: }
279:
280: public Object visit(NotExpression node) {
281: node.setExpression(visitExpression(node.getExpression()));
282: return node;
283: }
284:
285: private Object visit(BinaryExpression node) {
286: node
287: .setLeftExpression(visitExpression(node
288: .getLeftExpression()));
289: node.setRightExpression(visitExpression(node
290: .getRightExpression()));
291: return node;
292: }
293:
294: public Object visit(ConcatenateExpression node) {
295: return visit((BinaryExpression) node);
296: }
297:
298: public Object visit(ArithmeticExpression node) {
299: return visit((BinaryExpression) node);
300: }
301:
302: public Object visit(RelationalExpression node) {
303: if (node.getIsaTypeName() != null) {
304: node.setLeftExpression(visitExpression(node
305: .getLeftExpression()));
306: node.getIsaTypeName().accept(this );
307: return node;
308: } else {
309: return visit((BinaryExpression) node);
310: }
311: }
312:
313: public Object visit(AndExpression node) {
314: return visit((BinaryExpression) node);
315: }
316:
317: public Object visit(OrExpression node) {
318: return visit((BinaryExpression) node);
319: }
320:
321: public Object visit(NullLiteral node) {
322: return node;
323: }
324:
325: public Object visit(BooleanLiteral node) {
326: return node;
327: }
328:
329: public Object visit(StringLiteral node) {
330: return node;
331: }
332:
333: public Object visit(NumberLiteral node) {
334: return node;
335: }
336:
337: /**
338: * All expressions pass through this method to ensure the expression's
339: * type is preserved.
340: */
341: protected Expression visitExpression(Expression expr) {
342: if (expr == null) {
343: return null;
344: }
345:
346: Expression newExpr = (Expression) expr.accept(this );
347: if (expr != newExpr) {
348: Type newType = newExpr.getType();
349:
350: if (newType == null || !newType.equals(expr.getType())) {
351: Iterator it = expr.getConversionChain().iterator();
352: while (it.hasNext()) {
353: Expression.Conversion conv = (Expression.Conversion) it
354: .next();
355: newExpr.convertTo(conv.getToType(), conv
356: .isCastPreferred());
357: }
358: }
359: }
360: return newExpr;
361: }
362:
363: /**
364: * Visit a Block to ensure that new Statement is a Block.
365: */
366: protected Block visitBlock(Block block) {
367: if (block == null) {
368: return null;
369: }
370:
371: Statement stmt = (Statement) block.accept(this );
372:
373: if (stmt instanceof Block) {
374: return (Block) stmt;
375: } else if (stmt != null) {
376: return new Block(stmt);
377: } else {
378: return new Block(block.getSourceInfo());
379: }
380: }
381:
382: // TODO: create a visitNode for all nodes to ensure scope is preserved?
383: }
|