1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package jdk.nashorn.api.tree; 26 27 import java.util.ArrayList; 28 import java.util.List; 29 import jdk.nashorn.internal.ir.AccessNode; 30 import jdk.nashorn.internal.ir.BinaryNode; 31 import jdk.nashorn.internal.ir.Block; 32 import jdk.nashorn.internal.ir.BlockStatement; 33 import jdk.nashorn.internal.ir.BreakNode; 34 import jdk.nashorn.internal.ir.CallNode; 35 import jdk.nashorn.internal.ir.CaseNode; 36 import jdk.nashorn.internal.ir.CatchNode; 37 import jdk.nashorn.internal.ir.ContinueNode; 38 import jdk.nashorn.internal.ir.DebuggerNode; 39 import jdk.nashorn.internal.ir.EmptyNode; 40 import jdk.nashorn.internal.ir.ErrorNode; 41 import jdk.nashorn.internal.ir.Expression; 42 import jdk.nashorn.internal.ir.ExpressionStatement; 43 import jdk.nashorn.internal.ir.ForNode; 44 import jdk.nashorn.internal.ir.FunctionNode; 45 import jdk.nashorn.internal.ir.IdentNode; 46 import jdk.nashorn.internal.ir.IfNode; 47 import jdk.nashorn.internal.ir.IndexNode; 48 import jdk.nashorn.internal.ir.LabelNode; 49 import jdk.nashorn.internal.ir.LexicalContext; 50 import jdk.nashorn.internal.ir.LiteralNode; 51 import jdk.nashorn.internal.ir.Node; 52 import jdk.nashorn.internal.ir.ObjectNode; 53 import jdk.nashorn.internal.ir.PropertyNode; 54 import jdk.nashorn.internal.ir.ReturnNode; 55 import jdk.nashorn.internal.ir.RuntimeNode; 56 import jdk.nashorn.internal.ir.SplitNode; 57 import jdk.nashorn.internal.ir.Statement; 58 import jdk.nashorn.internal.ir.SwitchNode; 59 import jdk.nashorn.internal.ir.TernaryNode; 60 import jdk.nashorn.internal.ir.ThrowNode; 61 import jdk.nashorn.internal.ir.TryNode; 62 import jdk.nashorn.internal.ir.UnaryNode; 63 import jdk.nashorn.internal.ir.VarNode; 64 import jdk.nashorn.internal.ir.WhileNode; 65 import jdk.nashorn.internal.ir.WithNode; 66 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 67 import jdk.nashorn.internal.parser.Lexer; 68 import jdk.nashorn.internal.parser.TokenType; 69 70 /** 71 * This class translates from nashorn IR Node objects 72 * to nashorn parser API Tree objects. 73 */ 74 final class IRTranslator extends NodeVisitor<LexicalContext> { 75 76 public IRTranslator() { 77 super(new LexicalContext()); 78 } 79 80 // currently translated Statement 81 private StatementTreeImpl curStat; 82 // currently translated Expression 83 private ExpressionTreeImpl curExpr; 84 85 // entry point for translator 86 CompilationUnitTree translate(final FunctionNode node) { 87 if (node == null) { 88 return null; 89 } 90 91 assert (node.getKind() == FunctionNode.Kind.SCRIPT) : "script function expected"; 92 93 final Block body = node.getBody(); 94 return new CompilationUnitTreeImpl(node, 95 translateStats(body != null? body.getStatements() : null)); 96 } 97 98 @Override 99 public boolean enterAccessNode(final AccessNode accessNode) { 100 curExpr = new MemberSelectTreeImpl(accessNode, translateExpr(accessNode.getBase())); 101 return false; 102 } 103 104 @Override 105 public boolean enterBlock(final Block block) { 106 // FIXME: revisit this! 107 if (block.isSynthetic()) { 108 final int statCount = block.getStatementCount(); 109 switch (statCount) { 110 case 0: { 111 final EmptyNode emptyNode = new EmptyNode(-1, block.getToken(), block.getFinish()); 112 curStat = new EmptyStatementTreeImpl(emptyNode); 113 return false; 114 } 115 case 1: { 116 curStat = translateStat(block.getStatements().get(0)); 117 return false; 118 } 119 } 120 } 121 122 curStat = new BlockTreeImpl(block, 123 translateStats(block.getStatements())); 124 return false; 125 } 126 127 @Override 128 public boolean enterBinaryNode(final BinaryNode binaryNode) { 129 if (binaryNode.isAssignment()) { 130 final ExpressionTree srcTree = translateExpr(binaryNode.getAssignmentSource()); 131 final ExpressionTree destTree = translateExpr(binaryNode.getAssignmentDest()); 132 133 if (binaryNode.tokenType() == TokenType.ASSIGN) { 134 curExpr = new AssignmentTreeImpl(binaryNode, destTree, srcTree); 135 } else { 136 curExpr = new CompoundAssignmentTreeImpl(binaryNode, destTree, srcTree); 137 } 138 } else { 139 final ExpressionTree leftTree = translateExpr(binaryNode.lhs()); 140 final ExpressionTree rightTree = translateExpr(binaryNode.rhs()); 141 142 if (binaryNode.tokenType() == TokenType.INSTANCEOF) { 143 curExpr = new InstanceOfTreeImpl(binaryNode, leftTree, rightTree); 144 } else { 145 curExpr = new BinaryTreeImpl(binaryNode, leftTree, rightTree); 146 } 147 } 148 149 return false; 150 } 151 152 @Override 153 public boolean enterBreakNode(final BreakNode breakNode) { 154 curStat = new BreakTreeImpl(breakNode); 155 return false; 156 } 157 158 @Override 159 public boolean enterCallNode(final CallNode callNode) { 160 curExpr = null; 161 callNode.getFunction().accept(this); 162 final ExpressionTree funcTree = curExpr; 163 final List<? extends ExpressionTree> argTrees = translateExprs(callNode.getArgs()); 164 curExpr = new FunctionCallTreeImpl(callNode, funcTree, argTrees); 165 return false; 166 } 167 168 @Override 169 public boolean enterCaseNode(final CaseNode caseNode) { 170 assert false : "should not reach here!"; 171 return false; 172 } 173 174 @Override 175 public boolean enterCatchNode(final CatchNode catchNode) { 176 assert false : "should not reach here"; 177 return false; 178 } 179 180 @Override 181 public boolean enterContinueNode(final ContinueNode continueNode) { 182 curStat = new ContinueTreeImpl(continueNode); 183 return false; 184 } 185 186 @Override 187 public boolean enterDebuggerNode(final DebuggerNode debuggerNode) { 188 curStat = new DebuggerTreeImpl(debuggerNode); 189 return false; 190 } 191 192 @Override 193 public boolean enterEmptyNode(final EmptyNode emptyNode) { 194 curStat = new EmptyStatementTreeImpl(emptyNode); 195 return false; 196 } 197 198 @Override 199 public boolean enterErrorNode(final ErrorNode errorNode) { 200 curExpr = new ErroneousTreeImpl(errorNode); 201 return false; 202 } 203 204 @Override 205 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { 206 curStat = new ExpressionStatementTreeImpl(expressionStatement, 207 translateExpr(expressionStatement.getExpression())); 208 return false; 209 } 210 211 @Override 212 public boolean enterBlockStatement(final BlockStatement blockStatement) { 213 final Block block = blockStatement.getBlock(); 214 if (blockStatement.isSynthetic()) { 215 assert block != null && block.getStatements() != null && block.getStatements().size() == 1; 216 curStat = translateStat(block.getStatements().get(0)); 217 } else { 218 curStat = new BlockTreeImpl(blockStatement, 219 translateStats(block != null? block.getStatements() : null)); 220 } 221 return false; 222 } 223 224 @Override 225 public boolean enterForNode(final ForNode forNode) { 226 if (forNode.isForIn()) { 227 curStat = new ForInLoopTreeImpl(forNode, 228 translateExpr(forNode.getInit()), 229 translateExpr(forNode.getModify()), 230 translateBlock(forNode.getBody())); 231 } else { 232 curStat = new ForLoopTreeImpl(forNode, 233 translateExpr(forNode.getInit()), 234 translateExpr(forNode.getTest()), 235 translateExpr(forNode.getModify()), 236 translateBlock(forNode.getBody())); 237 } 238 239 return false; 240 } 241 242 @Override 243 public boolean enterFunctionNode(final FunctionNode functionNode) { 244 assert !functionNode.isDeclared() : "should not reach here for function declaration"; 245 246 final List<? extends ExpressionTree> paramTrees 247 = translateExprs(functionNode.getParameters()); 248 final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody()); 249 curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree); 250 251 return false; 252 } 253 254 @Override 255 public boolean enterIdentNode(final IdentNode identNode) { 256 curExpr = new IdentifierTreeImpl(identNode); 257 return false; 258 } 259 260 @Override 261 public boolean enterIfNode(final IfNode ifNode) { 262 curStat = new IfTreeImpl(ifNode, 263 translateExpr(ifNode.getTest()), 264 translateBlock(ifNode.getPass()), 265 translateBlock(ifNode.getFail())); 266 return false; 267 } 268 269 @Override 270 public boolean enterIndexNode(final IndexNode indexNode) { 271 curExpr = new ArrayAccessTreeImpl(indexNode, 272 translateExpr(indexNode.getBase()), 273 translateExpr(indexNode.getIndex())); 274 return false; 275 } 276 277 @Override 278 public boolean enterLabelNode(final LabelNode labelNode) { 279 curStat = new LabeledStatementTreeImpl(labelNode, 280 translateBlock(labelNode.getBody())); 281 return false; 282 } 283 284 @Override 285 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 286 final Object value = literalNode.getValue(); 287 if (value instanceof Lexer.RegexToken) { 288 curExpr = new RegExpLiteralTreeImpl(literalNode); 289 } else if (literalNode.isArray()) { 290 final List<Expression> exprNodes = literalNode.getElementExpressions(); 291 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprNodes.size()); 292 for (final Node node : exprNodes) { 293 if (node == null) { 294 exprTrees.add(null); 295 } else { 296 curExpr = null; 297 node.accept(this); 298 assert curExpr != null : "null for " + node; 299 exprTrees.add(curExpr); 300 } 301 } 302 curExpr = new ArrayLiteralTreeImpl(literalNode, exprTrees); 303 } else { 304 curExpr = new LiteralTreeImpl(literalNode); 305 } 306 307 return false; 308 } 309 310 @Override 311 public boolean enterObjectNode(final ObjectNode objectNode) { 312 final List<PropertyNode> propNodes = objectNode.getElements(); 313 final List<PropertyTreeImpl> propTrees = new ArrayList<>(propNodes.size()); 314 for (final PropertyNode propNode : propNodes) { 315 propTrees.add(new PropertyTreeImpl(propNode, 316 translateExpr(propNode.getKey()), 317 translateExpr(propNode.getValue()), 318 (FunctionExpressionTree) translateExpr(propNode.getGetter()), 319 (FunctionExpressionTree) translateExpr(propNode.getSetter()))); 320 } 321 curExpr = new ObjectLiteralTreeImpl(objectNode, propTrees); 322 return false; 323 } 324 325 @Override 326 public boolean enterPropertyNode(final PropertyNode propertyNode) { 327 assert false : "should not reach here!"; 328 return false; 329 } 330 331 @Override 332 public boolean enterReturnNode(final ReturnNode returnNode) { 333 curStat = new ReturnTreeImpl(returnNode, 334 translateExpr(returnNode.getExpression())); 335 return false; 336 } 337 338 @Override 339 public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 340 assert false : "should not reach here: RuntimeNode"; 341 return false; 342 } 343 344 @Override 345 public boolean enterSplitNode(final SplitNode splitNode) { 346 assert false : "should not reach here!"; 347 return false; 348 } 349 350 @Override 351 public boolean enterSwitchNode(final SwitchNode switchNode) { 352 final List<CaseNode> caseNodes = switchNode.getCases(); 353 final List<CaseTreeImpl> caseTrees = new ArrayList<>(caseNodes.size()); 354 for (final CaseNode caseNode : caseNodes) { 355 final Block body = caseNode.getBody(); 356 caseTrees.add( 357 new CaseTreeImpl(caseNode, 358 translateExpr(caseNode.getTest()), 359 translateStats(body != null? body.getStatements() : null))); 360 } 361 362 curStat = new SwitchTreeImpl(switchNode, 363 translateExpr(switchNode.getExpression()), 364 caseTrees); 365 return false; 366 } 367 368 @Override 369 public boolean enterTernaryNode(final TernaryNode ternaryNode) { 370 curExpr = new ConditionalExpressionTreeImpl(ternaryNode, 371 translateExpr(ternaryNode.getTest()), 372 translateExpr(ternaryNode.getTrueExpression()), 373 translateExpr(ternaryNode.getFalseExpression())); 374 return false; 375 } 376 377 @Override 378 public boolean enterThrowNode(final ThrowNode throwNode) { 379 curStat = new ThrowTreeImpl(throwNode, 380 translateExpr(throwNode.getExpression())); 381 return false; 382 } 383 384 @Override 385 public boolean enterTryNode(final TryNode tryNode) { 386 final List<? extends CatchNode> catchNodes = tryNode.getCatches(); 387 final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size()); 388 for (final CatchNode catchNode : catchNodes) { 389 catchTrees.add(new CatchTreeImpl(catchNode, 390 translateIdent(catchNode.getException()), 391 (BlockTree) translateBlock(catchNode.getBody()), 392 translateExpr(catchNode.getExceptionCondition()))); 393 } 394 395 curStat = new TryTreeImpl(tryNode, 396 (BlockTree) translateBlock(tryNode.getBody()), 397 catchTrees, 398 (BlockTree) translateBlock(tryNode.getFinallyBody())); 399 400 return false; 401 } 402 403 @Override 404 public boolean enterUnaryNode(final UnaryNode unaryNode) { 405 if (unaryNode.tokenType() == TokenType.NEW) { 406 curExpr = new NewTreeImpl(unaryNode, 407 translateExpr(unaryNode.getExpression())); 408 } else { 409 curExpr = new UnaryTreeImpl(unaryNode, 410 translateExpr(unaryNode.getExpression())); 411 } 412 return false; 413 } 414 415 @Override 416 public boolean enterVarNode(final VarNode varNode) { 417 final Expression initNode = varNode.getInit(); 418 if (initNode instanceof FunctionNode && ((FunctionNode)initNode).isDeclared()) { 419 final FunctionNode funcNode = (FunctionNode) initNode; 420 421 final List<? extends ExpressionTree> paramTrees 422 = translateExprs(funcNode.getParameters()); 423 final BlockTree blockTree = (BlockTree) translateBlock(funcNode.getBody()); 424 curStat = new FunctionDeclarationTreeImpl(varNode, paramTrees, blockTree); 425 } else { 426 curStat = new VariableTreeImpl(varNode, translateExpr(initNode)); 427 } 428 429 return false; 430 } 431 432 @Override 433 public boolean enterWhileNode(final WhileNode whileNode) { 434 final ExpressionTree condTree = translateExpr(whileNode.getTest()); 435 final StatementTree statTree = translateBlock(whileNode.getBody()); 436 437 if (whileNode.isDoWhile()) { 438 curStat = new DoWhileLoopTreeImpl(whileNode, condTree, statTree); 439 } else { 440 curStat = new WhileLoopTreeImpl(whileNode, condTree, statTree); 441 } 442 443 return false; 444 } 445 446 @Override 447 public boolean enterWithNode(final WithNode withNode) { 448 curStat = new WithTreeImpl(withNode, 449 translateExpr(withNode.getExpression()), 450 translateBlock(withNode.getBody())); 451 452 return false; 453 } 454 455 private StatementTree translateBlock(final Block blockNode) { 456 if (blockNode == null) { 457 return null; 458 } 459 curStat = null; 460 blockNode.accept(this); 461 return curStat; 462 } 463 464 private List<? extends StatementTree> translateStats(final List<? extends Statement> stats) { 465 if (stats == null) { 466 return null; 467 } 468 final List<StatementTreeImpl> statTrees = new ArrayList<>(stats.size()); 469 for (final Statement stat : stats) { 470 curStat = null; 471 stat.accept(this); 472 assert curStat != null; 473 statTrees.add(curStat); 474 } 475 return statTrees; 476 } 477 478 private List<? extends ExpressionTree> translateExprs(final List<? extends Expression> exprs) { 479 if (exprs == null) { 480 return null; 481 } 482 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprs.size()); 483 for (final Expression expr : exprs) { 484 curExpr = null; 485 expr.accept(this); 486 assert curExpr != null; 487 exprTrees.add(curExpr); 488 } 489 return exprTrees; 490 } 491 492 private ExpressionTreeImpl translateExpr(final Expression expr) { 493 if (expr == null) { 494 return null; 495 } 496 497 curExpr = null; 498 expr.accept(this); 499 assert curExpr != null : "null for " + expr; 500 return curExpr; 501 } 502 503 private StatementTreeImpl translateStat(final Statement stat) { 504 if (stat == null) { 505 return null; 506 } 507 508 curStat = null; 509 stat.accept(this); 510 assert curStat != null : "null for " + stat; 511 return curStat; 512 } 513 514 private IdentifierTree translateIdent(final IdentNode ident) { 515 return new IdentifierTreeImpl(ident); 516 } 517 }