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 */
043 public class IRFactory {
044
045 public IRFactory(TokenStream ts) {
046 this.ts = ts;
047 }
048
049 /**
050 * Script (for associating file/url names with toplevel scripts.)
051 */
052 public Object createScript(Object body, String sourceName,
053 int baseLineno, int endLineno, Object source)
054 {
055 Node result = new Node(TokenStream.SCRIPT);
056 Node children = ((Node) body).getFirstChild();
057 if (children != null)
058 result.addChildrenToBack(children);
059
060 result.putProp(Node.SOURCENAME_PROP, sourceName);
061 result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
062 result.putIntProp(Node.END_LINENO_PROP, endLineno);
063 if (source != null)
064 result.putProp(Node.SOURCE_PROP, source);
065 return result;
066 }
067
068 /**
069 * Leaf
070 */
071 public Object createLeaf(int nodeType) {
072 return new Node(nodeType);
073 }
074
075 public Object createLeaf(int nodeType, int nodeOp) {
076 return new Node(nodeType, nodeOp);
077 }
078
079 public int getLeafType(Object leaf) {
080 Node n = (Node) leaf;
081 return n.getType();
082 }
083
084 /**
085 * Statement leaf nodes.
086 */
087
088 public Object createSwitch(int lineno) {
089 return new Node(TokenStream.SWITCH, lineno);
090 }
091
092 public Object createVariables(int lineno) {
093 return new Node(TokenStream.VAR, lineno);
094 }
095
096 public Object createExprStatement(Object expr, int lineno) {
097 return new Node(TokenStream.EXPRSTMT, (Node) expr, lineno);
098 }
099
100 /**
101 * Name
102 */
103 public Object createName(String name) {
104 return Node.newString(TokenStream.NAME, name);
105 }
106
107 /**
108 * String (for literals)
109 */
110 public Object createString(String string) {
111 return Node.newString(string);
112 }
113
114 /**
115 * Number (for literals)
116 */
117 public Object createNumber(int number) {
118 return Node.newNumber(number);
119 }
120
121 public Object createNumber(double number) {
122 return Node.newNumber(number);
123 }
124
125 /**
126 * Catch clause of try/catch/finally
127 * @param varName the name of the variable to bind to the exception
128 * @param catchCond the condition under which to catch the exception.
129 * May be null if no condition is given.
130 * @param stmts the statements in the catch clause
131 * @param lineno the starting line number of the catch clause
132 */
133 public Object createCatch(String varName, Object catchCond, Object stmts,
134 int lineno)
135 {
136 if (catchCond == null) {
137 catchCond = new Node(TokenStream.PRIMARY, TokenStream.TRUE);
138 }
139 return new Node(TokenStream.CATCH, (Node)createName(varName),
140 (Node)catchCond, (Node)stmts, lineno);
141 }
142
143 /**
144 * Throw
145 */
146 public Object createThrow(Object expr, int lineno) {
147 return new Node(TokenStream.THROW, (Node)expr, lineno);
148 }
149
150 /**
151 * Return
152 */
153 public Object createReturn(Object expr, int lineno) {
154 return expr == null
155 ? new Node(TokenStream.RETURN, lineno)
156 : new Node(TokenStream.RETURN, (Node)expr, lineno);
157 }
158
159 /**
160 * Label
161 */
162 public Object createLabel(String label, int lineno) {
163 Node result = new Node(TokenStream.LABEL, lineno);
164 Node name = Node.newString(TokenStream.NAME, label);
165 result.addChildToBack(name);
166 return result;
167 }
168
169 /**
170 * Break (possibly labeled)
171 */
172 public Object createBreak(String label, int lineno) {
173 Node result = new Node(TokenStream.BREAK, lineno);
174 if (label == null) {
175 return result;
176 } else {
177 Node name = Node.newString(TokenStream.NAME, label);
178 result.addChildToBack(name);
179 return result;
180 }
181 }
182
183 /**
184 * Continue (possibly labeled)
185 */
186 public Object createContinue(String label, int lineno) {
187 Node result = new Node(TokenStream.CONTINUE, lineno);
188 if (label == null) {
189 return result;
190 } else {
191 Node name = Node.newString(TokenStream.NAME, label);
192 result.addChildToBack(name);
193 return result;
194 }
195 }
196
197 /**
198 * debugger
199 */
200 public Object createDebugger(int lineno) {
201 Node result = new Node(TokenStream.DEBUGGER, lineno);
202 return result;
203 }
204
205 /**
206 * Statement block
207 * Creates the empty statement block
208 * Must make subsequent calls to add statements to the node
209 */
210 public Object createBlock(int lineno) {
211 return new Node(TokenStream.BLOCK, lineno);
212 }
213
214 public Object createFunction(String name, Object args, Object statements,
215 String sourceName, int baseLineno,
216 int endLineno, Object source,
217 boolean isExpr)
218 {
219 Node f = new Node(TokenStream.FUNCTION,
220 Node.newString(TokenStream.NAME,
221 name == null ? "" : name),
222 (Node)args, (Node)statements, baseLineno);
223
224 f.putProp(Node.SOURCENAME_PROP, sourceName);
225 f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
226 f.putIntProp(Node.END_LINENO_PROP, endLineno);
227 if (source != null)
228 f.putProp(Node.SOURCE_PROP, source);
229
230 return f;
231 }
232
233 /**
234 * Add a child to the back of the given node. This function
235 * breaks the Factory abstraction, but it removes a requirement
236 * from implementors of Node.
237 */
238 public void addChildToBack(Object parent, Object child) {
239 ((Node)parent).addChildToBack((Node)child);
240 }
241
242 /**
243 * While
244 */
245 public Object createWhile(Object cond, Object body, int lineno) {
246 return new Node(TokenStream.WHILE, (Node)cond, (Node)body, lineno);
247 }
248
249 /**
250 * DoWhile
251 */
252 public Object createDoWhile(Object body, Object cond, int lineno) {
253 return new Node(TokenStream.DO, (Node)body, (Node)cond, lineno);
254 }
255
256 /**
257 * For
258 */
259 public Object createFor(Object init, Object test, Object incr,
260 Object body, int lineno)
261 {
262 return new Node(TokenStream.FOR, (Node)init, (Node)test, (Node)incr,
263 (Node)body);
264 }
265
266 /**
267 * For .. In
268 *
269 */
270 public Object createForIn(Object lhs, Object obj, Object body, int lineno) {
271 return new Node(TokenStream.FOR, (Node)lhs, (Node)obj, (Node)body);
272 }
273
274 /**
275 * Try/Catch/Finally
276 */
277 public Object createTryCatchFinally(Object tryblock, Object catchblocks,
278 Object finallyblock, int lineno)
279 {
280 if (finallyblock == null) {
281 return new Node(TokenStream.TRY, (Node)tryblock, (Node)catchblocks);
282 }
283 return new Node(TokenStream.TRY, (Node)tryblock,
284 (Node)catchblocks, (Node)finallyblock);
285 }
286
287 /**
288 * Throw, Return, Label, Break and Continue are defined in ASTFactory.
289 */
290
291 /**
292 * With
293 */
294 public Object createWith(Object obj, Object body, int lineno) {
295 return new Node(TokenStream.WITH, (Node)obj, (Node)body, lineno);
296 }
297
298 /**
299 * Array Literal
300 */
301 public Object createArrayLiteral(Object obj) {
302 return obj;
303 }
304
305 /**
306 * Object Literals
307 */
308 public Object createObjectLiteral(Object obj) {
309 return obj;
310 }
311
312 /**
313 * Regular expressions
314 */
315 public Object createRegExp(String string, String flags) {
316 return flags.length() == 0
317 ? new Node(TokenStream.REGEXP,
318 Node.newString(string))
319 : new Node(TokenStream.REGEXP,
320 Node.newString(string),
321 Node.newString(flags));
322 }
323
324 /**
325 * If statement
326 */
327 public Object createIf(Object cond, Object ifTrue, Object ifFalse,
328 int lineno)
329 {
330 if (ifFalse == null)
331 return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue);
332 return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue, (Node)ifFalse);
333 }
334
335 public Object createTernary(Object cond, Object ifTrue, Object ifFalse) {
336 return new Node(TokenStream.HOOK,
337 (Node)cond, (Node)ifTrue, (Node)ifFalse);
338 }
339
340 /**
341 * Unary
342 */
343 public Object createUnary(int nodeType, Object child) {
344 Node childNode = (Node) child;
345 return new Node(nodeType, childNode);
346 }
347
348 public Object createUnary(int nodeType, int nodeOp, Object child) {
349 return new Node(nodeType, (Node)child, nodeOp);
350 }
351
352 /**
353 * Binary
354 */
355 public Object createBinary(int nodeType, Object left, Object right) {
356 Node temp;
357 switch (nodeType) {
358
359 case TokenStream.DOT:
360 nodeType = TokenStream.GETPROP;
361 Node idNode = (Node) right;
362 idNode.setType(TokenStream.STRING);
363 String id = idNode.getString();
364 if (id.equals("__proto__") || id.equals("__parent__")) {
365 Node result = new Node(nodeType, (Node) left);
366 result.putProp(Node.SPECIAL_PROP_PROP, id);
367 return result;
368 }
369 break;
370
371 case TokenStream.LB:
372 // OPT: could optimize to GETPROP iff string can't be a number
373 nodeType = TokenStream.GETELEM;
374 break;
375 }
376 return new Node(nodeType, (Node)left, (Node)right);
377 }
378
379 public Object createBinary(int nodeType, int nodeOp, Object left,
380 Object right)
381 {
382 if (nodeType == TokenStream.ASSIGN) {
383 return createAssignment(nodeOp, (Node) left, (Node) right,
384 null, false);
385 }
386 return new Node(nodeType, (Node) left, (Node) right, nodeOp);
387 }
388
389 public Object createAssignment(int nodeOp, Node left, Node right,
390 Class convert, boolean postfix)
391 {
392 int nodeType = left.getType();
393 switch (nodeType) {
394 case TokenStream.NAME:
395 case TokenStream.GETPROP:
396 case TokenStream.GETELEM:
397 break;
398 default:
399 // TODO: This should be a ReferenceError--but that's a runtime
400 // exception. Should we compile an exception into the code?
401 reportError("msg.bad.lhs.assign");
402 }
403
404 return new Node(TokenStream.ASSIGN, left, right, nodeOp);
405 }
406
407 private void reportError(String msgResource) {
408
409 String message = Context.getMessage0(msgResource);
410 ts.reportSyntaxError(message, null);
411 }
412
413 // Only needed to get file/line information. Could create an interface
414 // that TokenStream implements if we want to make the connection less
415 // direct.
416 private TokenStream ts;
417 }