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 Context.reportError( 411 message, ts.getSourceName(), ts.getLineno(), 412 ts.getLine(), ts.getOffset()); 413 } 414 415 // Only needed to get file/line information. Could create an interface 416 // that TokenStream implements if we want to make the connection less 417 // direct. 418 private TokenStream ts; 419 }