001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * The contents of this file are subject to the Netscape Public
004: * License Version 1.1 (the "License"); you may not use this file
005: * except in compliance with the License. You may obtain a copy of
006: * the License at http://www.mozilla.org/NPL/
007: *
008: * Software distributed under the License is distributed on an "AS
009: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
010: * implied. See the License for the specific language governing
011: * rights and limitations under the License.
012: *
013: * The Original Code is Rhino code, released
014: * May 6, 1999.
015: *
016: * The Initial Developer of the Original Code is Netscape
017: * Communications Corporation. Portions created by Netscape are
018: * Copyright (C) 1997-1999 Netscape Communications Corporation. All
019: * Rights Reserved.
020: *
021: * Contributor(s):
022: * Norris Boyd
023: *
024: * Alternatively, the contents of this file may be used under the
025: * terms of the GNU Public License (the "GPL"), in which case the
026: * provisions of the GPL are applicable instead of those above.
027: * If you wish to allow use of your version of this file only
028: * under the terms of the GPL and not to allow others to use your
029: * version of this file under the NPL, indicate your decision by
030: * deleting the provisions above and replace them with the notice
031: * and other provisions required by the GPL. If you do not delete
032: * the provisions above, a recipient may use your version of this
033: * file under either the NPL or the GPL.
034: */
035:
036: package com.google.gwt.dev.js.rhino;
037:
038: /**
039: * This class allows the creation of nodes, and follows the Factory pattern.
040: *
041: * @see Node
042: * @author Mike McCabe
043: * @author Norris Boyd
044: */
045: public class IRFactory {
046:
047: public IRFactory(TokenStream ts) {
048: this .ts = ts;
049: }
050:
051: /**
052: * Script (for associating file/url names with toplevel scripts.)
053: */
054: public Object createScript(Object body, String sourceName,
055: int baseLineno, int endLineno, Object source) {
056: Node result = new Node(TokenStream.SCRIPT);
057: Node children = ((Node) body).getFirstChild();
058: if (children != null)
059: result.addChildrenToBack(children);
060:
061: result.putProp(Node.SOURCENAME_PROP, sourceName);
062: result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
063: result.putIntProp(Node.END_LINENO_PROP, endLineno);
064: if (source != null)
065: result.putProp(Node.SOURCE_PROP, source);
066: return result;
067: }
068:
069: /**
070: * Leaf
071: */
072: public Object createLeaf(int nodeType) {
073: return new Node(nodeType);
074: }
075:
076: public Object createLeaf(int nodeType, int nodeOp) {
077: return new Node(nodeType, nodeOp);
078: }
079:
080: public int getLeafType(Object leaf) {
081: Node n = (Node) leaf;
082: return n.getType();
083: }
084:
085: /**
086: * Statement leaf nodes.
087: */
088:
089: public Object createSwitch(int lineno) {
090: return new Node(TokenStream.SWITCH, lineno);
091: }
092:
093: public Object createVariables(int lineno) {
094: return new Node(TokenStream.VAR, lineno);
095: }
096:
097: public Object createExprStatement(Object expr, int lineno) {
098: return new Node(TokenStream.EXPRSTMT, (Node) expr, lineno);
099: }
100:
101: /**
102: * Name
103: */
104: public Object createName(String name) {
105: return Node.newString(TokenStream.NAME, name);
106: }
107:
108: /**
109: * String (for literals)
110: */
111: public Object createString(String string) {
112: return Node.newString(string);
113: }
114:
115: /**
116: * Number (for literals)
117: */
118: public Object createNumber(double number) {
119: return Node.newNumber(number);
120: }
121:
122: /**
123: * Catch clause of try/catch/finally
124: * @param varName the name of the variable to bind to the exception
125: * @param catchCond the condition under which to catch the exception.
126: * May be null if no condition is given.
127: * @param stmts the statements in the catch clause
128: * @param lineno the starting line number of the catch clause
129: */
130: public Object createCatch(String varName, Object catchCond,
131: Object stmts, int lineno) {
132: if (catchCond == null) {
133: catchCond = new Node(TokenStream.PRIMARY, TokenStream.TRUE);
134: }
135: return new Node(TokenStream.CATCH, (Node) createName(varName),
136: (Node) catchCond, (Node) stmts, lineno);
137: }
138:
139: /**
140: * Throw
141: */
142: public Object createThrow(Object expr, int lineno) {
143: return new Node(TokenStream.THROW, (Node) expr, lineno);
144: }
145:
146: /**
147: * Return
148: */
149: public Object createReturn(Object expr, int lineno) {
150: return expr == null ? new Node(TokenStream.RETURN, lineno)
151: : new Node(TokenStream.RETURN, (Node) expr, lineno);
152: }
153:
154: /**
155: * Label
156: */
157: public Object createLabel(String label, int lineno) {
158: Node result = new Node(TokenStream.LABEL, lineno);
159: Node name = Node.newString(TokenStream.NAME, label);
160: result.addChildToBack(name);
161: return result;
162: }
163:
164: /**
165: * Break (possibly labeled)
166: */
167: public Object createBreak(String label, int lineno) {
168: Node result = new Node(TokenStream.BREAK, lineno);
169: if (label == null) {
170: return result;
171: } else {
172: Node name = Node.newString(TokenStream.NAME, label);
173: result.addChildToBack(name);
174: return result;
175: }
176: }
177:
178: /**
179: * Continue (possibly labeled)
180: */
181: public Object createContinue(String label, int lineno) {
182: Node result = new Node(TokenStream.CONTINUE, lineno);
183: if (label == null) {
184: return result;
185: } else {
186: Node name = Node.newString(TokenStream.NAME, label);
187: result.addChildToBack(name);
188: return result;
189: }
190: }
191:
192: /**
193: * debugger
194: */
195: public Object createDebugger(int lineno) {
196: Node result = new Node(TokenStream.DEBUGGER, lineno);
197: return result;
198: }
199:
200: /**
201: * Statement block
202: * Creates the empty statement block
203: * Must make subsequent calls to add statements to the node
204: */
205: public Object createBlock(int lineno) {
206: return new Node(TokenStream.BLOCK, lineno);
207: }
208:
209: public Object createFunction(String name, Object args,
210: Object statements, String sourceName, int baseLineno,
211: int endLineno, Object source, boolean isExpr) {
212: Node f = new Node(TokenStream.FUNCTION, Node.newString(
213: TokenStream.NAME, name == null ? "" : name),
214: (Node) args, (Node) statements, baseLineno);
215:
216: f.putProp(Node.SOURCENAME_PROP, sourceName);
217: f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
218: f.putIntProp(Node.END_LINENO_PROP, endLineno);
219: if (source != null)
220: f.putProp(Node.SOURCE_PROP, source);
221:
222: return f;
223: }
224:
225: /**
226: * Add a child to the back of the given node. This function
227: * breaks the Factory abstraction, but it removes a requirement
228: * from implementors of Node.
229: */
230: public void addChildToBack(Object parent, Object child) {
231: ((Node) parent).addChildToBack((Node) child);
232: }
233:
234: /**
235: * While
236: */
237: public Object createWhile(Object cond, Object body, int lineno) {
238: return new Node(TokenStream.WHILE, (Node) cond, (Node) body,
239: lineno);
240: }
241:
242: /**
243: * DoWhile
244: */
245: public Object createDoWhile(Object body, Object cond, int lineno) {
246: return new Node(TokenStream.DO, (Node) body, (Node) cond,
247: lineno);
248: }
249:
250: /**
251: * For
252: */
253: public Object createFor(Object init, Object test, Object incr,
254: Object body, int lineno) {
255: return new Node(TokenStream.FOR, (Node) init, (Node) test,
256: (Node) incr, (Node) body);
257: }
258:
259: /**
260: * For .. In
261: *
262: */
263: public Object createForIn(Object lhs, Object obj, Object body,
264: int lineno) {
265: return new Node(TokenStream.FOR, (Node) lhs, (Node) obj,
266: (Node) body);
267: }
268:
269: /**
270: * Try/Catch/Finally
271: */
272: public Object createTryCatchFinally(Object tryblock,
273: Object catchblocks, Object finallyblock, int lineno) {
274: if (finallyblock == null) {
275: return new Node(TokenStream.TRY, (Node) tryblock,
276: (Node) catchblocks);
277: }
278: return new Node(TokenStream.TRY, (Node) tryblock,
279: (Node) catchblocks, (Node) finallyblock);
280: }
281:
282: /**
283: * Throw, Return, Label, Break and Continue are defined in ASTFactory.
284: */
285:
286: /**
287: * With
288: */
289: public Object createWith(Object obj, Object body, int lineno) {
290: return new Node(TokenStream.WITH, (Node) obj, (Node) body,
291: lineno);
292: }
293:
294: /**
295: * Array Literal
296: */
297: public Object createArrayLiteral(Object obj) {
298: return obj;
299: }
300:
301: /**
302: * Object Literals
303: */
304: public Object createObjectLiteral(Object obj) {
305: return obj;
306: }
307:
308: /**
309: * Regular expressions
310: */
311: public Object createRegExp(String string, String flags) {
312: return flags.length() == 0 ? new Node(TokenStream.REGEXP, Node
313: .newString(string)) : new Node(TokenStream.REGEXP, Node
314: .newString(string), Node.newString(flags));
315: }
316:
317: /**
318: * If statement
319: */
320: public Object createIf(Object cond, Object ifTrue, Object ifFalse,
321: int lineno) {
322: if (ifFalse == null)
323: return new Node(TokenStream.IF, (Node) cond, (Node) ifTrue);
324: return new Node(TokenStream.IF, (Node) cond, (Node) ifTrue,
325: (Node) ifFalse);
326: }
327:
328: public Object createTernary(Object cond, Object ifTrue,
329: Object ifFalse) {
330: return new Node(TokenStream.HOOK, (Node) cond, (Node) ifTrue,
331: (Node) ifFalse);
332: }
333:
334: /**
335: * Unary
336: */
337: public Object createUnary(int nodeType, Object child) {
338: Node childNode = (Node) child;
339: return new Node(nodeType, childNode);
340: }
341:
342: public Object createUnary(int nodeType, int nodeOp, Object child) {
343: return new Node(nodeType, (Node) child, nodeOp);
344: }
345:
346: /**
347: * Binary
348: */
349: public Object createBinary(int nodeType, Object left, Object right) {
350: Node temp;
351: switch (nodeType) {
352:
353: case TokenStream.DOT:
354: nodeType = TokenStream.GETPROP;
355: Node idNode = (Node) right;
356: idNode.setType(TokenStream.STRING);
357: String id = idNode.getString();
358: if (id.equals("__proto__") || id.equals("__parent__")) {
359: Node result = new Node(nodeType, (Node) left);
360: result.putProp(Node.SPECIAL_PROP_PROP, id);
361: return result;
362: }
363: break;
364:
365: case TokenStream.LB:
366: // OPT: could optimize to GETPROP iff string can't be a number
367: nodeType = TokenStream.GETELEM;
368: break;
369: }
370: return new Node(nodeType, (Node) left, (Node) right);
371: }
372:
373: public Object createBinary(int nodeType, int nodeOp, Object left,
374: Object right) {
375: if (nodeType == TokenStream.ASSIGN) {
376: return createAssignment(nodeOp, (Node) left, (Node) right,
377: null, false);
378: }
379: return new Node(nodeType, (Node) left, (Node) right, nodeOp);
380: }
381:
382: public Object createAssignment(int nodeOp, Node left, Node right,
383: Class convert, boolean postfix) {
384: int nodeType = left.getType();
385: switch (nodeType) {
386: case TokenStream.NAME:
387: case TokenStream.GETPROP:
388: case TokenStream.GETELEM:
389: break;
390: default:
391: // TODO: This should be a ReferenceError--but that's a runtime
392: // exception. Should we compile an exception into the code?
393: reportError("msg.bad.lhs.assign");
394: }
395:
396: return new Node(TokenStream.ASSIGN, left, right, nodeOp);
397: }
398:
399: private Node createConvert(Class toType, Node expr) {
400: if (toType == null)
401: return expr;
402: Node result = new Node(TokenStream.CONVERT, expr);
403: result.putProp(Node.TYPE_PROP, Number.class);
404: return result;
405: }
406:
407: public static boolean hasSideEffects(Node exprTree) {
408: switch (exprTree.getType()) {
409: case TokenStream.INC:
410: case TokenStream.DEC:
411: case TokenStream.SETPROP:
412: case TokenStream.SETELEM:
413: case TokenStream.SETNAME:
414: case TokenStream.CALL:
415: case TokenStream.NEW:
416: return true;
417: default:
418: Node child = exprTree.getFirstChild();
419: while (child != null) {
420: if (hasSideEffects(child))
421: return true;
422: else
423: child = child.getNext();
424: }
425: break;
426: }
427: return false;
428: }
429:
430: private void reportError(String msgResource) {
431:
432: String message = Context.getMessage0(msgResource);
433: Context.reportError(message, ts.getSourceName(),
434: ts.getLineno(), ts.getLine(), ts.getOffset());
435: }
436:
437: // Only needed to get file/line information. Could create an interface
438: // that TokenStream implements if we want to make the connection less
439: // direct.
440: private TokenStream ts;
441: }
|