IRTranslator.java revision 1220:8bbea2def25f
1112158Sdas/* 2112158Sdas * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3112158Sdas * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4112158Sdas * 5112158Sdas * This code is free software; you can redistribute it and/or modify it 6112158Sdas * under the terms of the GNU General Public License version 2 only, as 7112158Sdas * published by the Free Software Foundation. Oracle designates this 8112158Sdas * particular file as subject to the "Classpath" exception as provided 9112158Sdas * by Oracle in the LICENSE file that accompanied this code. 10112158Sdas * 11112158Sdas * This code is distributed in the hope that it will be useful, but WITHOUT 12112158Sdas * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13112158Sdas * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14112158Sdas * version 2 for more details (a copy is included in the LICENSE file that 15112158Sdas * accompanied this code). 16112158Sdas * 17112158Sdas * You should have received a copy of the GNU General Public License version 18112158Sdas * 2 along with this work; if not, write to the Free Software Foundation, 19112158Sdas * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20112158Sdas * 21112158Sdas * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22112158Sdas * or visit www.oracle.com if you need additional information or have any 23112158Sdas * questions. 24112158Sdas */ 25112158Sdaspackage jdk.nashorn.api.tree; 26112158Sdas 27112158Sdasimport java.util.ArrayList; 28112158Sdasimport java.util.Comparator; 29165743Sdasimport java.util.List; 30165743Sdasimport jdk.nashorn.internal.ir.AccessNode; 31112158Sdasimport jdk.nashorn.internal.ir.BinaryNode; 32112158Sdasimport jdk.nashorn.internal.ir.Block; 33112158Sdasimport jdk.nashorn.internal.ir.BlockStatement; 34112158Sdasimport jdk.nashorn.internal.ir.BreakNode; 35112158Sdasimport jdk.nashorn.internal.ir.CallNode; 36112158Sdasimport jdk.nashorn.internal.ir.CaseNode; 37112158Sdasimport jdk.nashorn.internal.ir.CatchNode; 38112158Sdasimport jdk.nashorn.internal.ir.ContinueNode; 39112158Sdasimport jdk.nashorn.internal.ir.DebuggerNode; 40112158Sdasimport jdk.nashorn.internal.ir.EmptyNode; 41112158Sdasimport jdk.nashorn.internal.ir.ErrorNode; 42112158Sdasimport jdk.nashorn.internal.ir.Expression; 43112158Sdasimport jdk.nashorn.internal.ir.ExpressionStatement; 44112158Sdasimport jdk.nashorn.internal.ir.ForNode; 45112158Sdasimport jdk.nashorn.internal.ir.FunctionNode; 46112158Sdasimport jdk.nashorn.internal.ir.IdentNode; 47112158Sdasimport jdk.nashorn.internal.ir.IfNode; 48112158Sdasimport jdk.nashorn.internal.ir.IndexNode; 49112158Sdasimport jdk.nashorn.internal.ir.LabelNode; 50112158Sdasimport jdk.nashorn.internal.ir.LexicalContext; 51112158Sdasimport jdk.nashorn.internal.ir.LiteralNode; 52112158Sdasimport jdk.nashorn.internal.ir.Node; 53112158Sdasimport jdk.nashorn.internal.ir.ObjectNode; 54112158Sdasimport jdk.nashorn.internal.ir.PropertyNode; 55112158Sdasimport jdk.nashorn.internal.ir.ReturnNode; 56112158Sdasimport jdk.nashorn.internal.ir.RuntimeNode; 57112158Sdasimport jdk.nashorn.internal.ir.SplitNode; 58112158Sdasimport jdk.nashorn.internal.ir.Statement; 59112158Sdasimport jdk.nashorn.internal.ir.SwitchNode; 60112158Sdasimport jdk.nashorn.internal.ir.TernaryNode; 61112158Sdasimport jdk.nashorn.internal.ir.ThrowNode; 62112158Sdasimport jdk.nashorn.internal.ir.TryNode; 63112158Sdasimport jdk.nashorn.internal.ir.UnaryNode; 64112158Sdasimport jdk.nashorn.internal.ir.VarNode; 65112158Sdasimport jdk.nashorn.internal.ir.WhileNode; 66112158Sdasimport jdk.nashorn.internal.ir.WithNode; 67112158Sdasimport jdk.nashorn.internal.ir.visitor.NodeVisitor; 68112158Sdasimport jdk.nashorn.internal.parser.Lexer; 69112158Sdasimport jdk.nashorn.internal.parser.TokenType; 70112158Sdas 71112158Sdas/** 72112158Sdas * This class translates from nashorn IR Node objects 73112158Sdas * to nashorn parser API Tree objects. 74112158Sdas */ 75112158Sdasfinal class IRTranslator extends NodeVisitor<LexicalContext> { 76112158Sdas 77112158Sdas public IRTranslator() { 78112158Sdas super(new LexicalContext()); 79112158Sdas } 80112158Sdas 81112158Sdas // currently translated Statement 82112158Sdas private StatementTreeImpl curStat; 83112158Sdas // currently translated Expression 84112158Sdas private ExpressionTreeImpl curExpr; 85112158Sdas 86112158Sdas // entry point for translator 87112158Sdas CompilationUnitTree translate(final FunctionNode node) { 88112158Sdas if (node == null) { 89112158Sdas return null; 90112158Sdas } 91112158Sdas 92112158Sdas assert (node.getKind() == FunctionNode.Kind.SCRIPT) : "script function expected"; 93112158Sdas 94112158Sdas final Block body = node.getBody(); 95112158Sdas return new CompilationUnitTreeImpl(node, 96112158Sdas translateStats(body != null? getOrderedStatements(body.getStatements()) : null)); 97112158Sdas } 98112158Sdas 99 @Override 100 public boolean enterAccessNode(final AccessNode accessNode) { 101 curExpr = new MemberSelectTreeImpl(accessNode, translateExpr(accessNode.getBase())); 102 return false; 103 } 104 105 @Override 106 public boolean enterBlock(final Block block) { 107 return handleBlock(block, false); 108 } 109 110 @Override 111 public boolean enterBinaryNode(final BinaryNode binaryNode) { 112 if (binaryNode.isAssignment()) { 113 final ExpressionTree srcTree = translateExpr(binaryNode.getAssignmentSource()); 114 final ExpressionTree destTree = translateExpr(binaryNode.getAssignmentDest()); 115 116 if (binaryNode.tokenType() == TokenType.ASSIGN) { 117 curExpr = new AssignmentTreeImpl(binaryNode, destTree, srcTree); 118 } else { 119 curExpr = new CompoundAssignmentTreeImpl(binaryNode, destTree, srcTree); 120 } 121 } else { 122 final ExpressionTree leftTree = translateExpr(binaryNode.lhs()); 123 final ExpressionTree rightTree = translateExpr(binaryNode.rhs()); 124 125 if (binaryNode.tokenType() == TokenType.INSTANCEOF) { 126 curExpr = new InstanceOfTreeImpl(binaryNode, leftTree, rightTree); 127 } else { 128 curExpr = new BinaryTreeImpl(binaryNode, leftTree, rightTree); 129 } 130 } 131 132 return false; 133 } 134 135 @Override 136 public boolean enterBreakNode(final BreakNode breakNode) { 137 curStat = new BreakTreeImpl(breakNode); 138 return false; 139 } 140 141 @Override 142 public boolean enterCallNode(final CallNode callNode) { 143 curExpr = null; 144 callNode.getFunction().accept(this); 145 final ExpressionTree funcTree = curExpr; 146 final List<? extends ExpressionTree> argTrees = translateExprs(callNode.getArgs()); 147 curExpr = new FunctionCallTreeImpl(callNode, funcTree, argTrees); 148 return false; 149 } 150 151 @Override 152 public boolean enterCaseNode(final CaseNode caseNode) { 153 assert false : "should not reach here!"; 154 return false; 155 } 156 157 @Override 158 public boolean enterCatchNode(final CatchNode catchNode) { 159 assert false : "should not reach here"; 160 return false; 161 } 162 163 @Override 164 public boolean enterContinueNode(final ContinueNode continueNode) { 165 curStat = new ContinueTreeImpl(continueNode); 166 return false; 167 } 168 169 @Override 170 public boolean enterDebuggerNode(final DebuggerNode debuggerNode) { 171 curStat = new DebuggerTreeImpl(debuggerNode); 172 return false; 173 } 174 175 @Override 176 public boolean enterEmptyNode(final EmptyNode emptyNode) { 177 curStat = new EmptyStatementTreeImpl(emptyNode); 178 return false; 179 } 180 181 @Override 182 public boolean enterErrorNode(final ErrorNode errorNode) { 183 curExpr = new ErroneousTreeImpl(errorNode); 184 return false; 185 } 186 187 @Override 188 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { 189 curStat = new ExpressionStatementTreeImpl(expressionStatement, 190 translateExpr(expressionStatement.getExpression())); 191 return false; 192 } 193 194 @Override 195 public boolean enterBlockStatement(final BlockStatement blockStatement) { 196 final Block block = blockStatement.getBlock(); 197 if (blockStatement.isSynthetic()) { 198 assert block != null && block.getStatements() != null && block.getStatements().size() == 1; 199 curStat = translateStat(block.getStatements().get(0)); 200 } else { 201 curStat = new BlockTreeImpl(blockStatement, 202 translateStats(block != null? block.getStatements() : null)); 203 } 204 return false; 205 } 206 207 @Override 208 public boolean enterForNode(final ForNode forNode) { 209 if (forNode.isForIn()) { 210 curStat = new ForInLoopTreeImpl(forNode, 211 translateExpr(forNode.getInit()), 212 translateExpr(forNode.getModify()), 213 translateBlock(forNode.getBody())); 214 } else { 215 curStat = new ForLoopTreeImpl(forNode, 216 translateExpr(forNode.getInit()), 217 translateExpr(forNode.getTest()), 218 translateExpr(forNode.getModify()), 219 translateBlock(forNode.getBody())); 220 } 221 222 return false; 223 } 224 225 @Override 226 public boolean enterFunctionNode(final FunctionNode functionNode) { 227 assert !functionNode.isDeclared() : "should not reach here for function declaration"; 228 229 final List<? extends ExpressionTree> paramTrees 230 = translateExprs(functionNode.getParameters()); 231 final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody(), true); 232 curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree); 233 234 return false; 235 } 236 237 @Override 238 public boolean enterIdentNode(final IdentNode identNode) { 239 curExpr = new IdentifierTreeImpl(identNode); 240 return false; 241 } 242 243 @Override 244 public boolean enterIfNode(final IfNode ifNode) { 245 curStat = new IfTreeImpl(ifNode, 246 translateExpr(ifNode.getTest()), 247 translateBlock(ifNode.getPass()), 248 translateBlock(ifNode.getFail())); 249 return false; 250 } 251 252 @Override 253 public boolean enterIndexNode(final IndexNode indexNode) { 254 curExpr = new ArrayAccessTreeImpl(indexNode, 255 translateExpr(indexNode.getBase()), 256 translateExpr(indexNode.getIndex())); 257 return false; 258 } 259 260 @Override 261 public boolean enterLabelNode(final LabelNode labelNode) { 262 curStat = new LabeledStatementTreeImpl(labelNode, 263 translateBlock(labelNode.getBody())); 264 return false; 265 } 266 267 @Override 268 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 269 final Object value = literalNode.getValue(); 270 if (value instanceof Lexer.RegexToken) { 271 curExpr = new RegExpLiteralTreeImpl(literalNode); 272 } else if (literalNode.isArray()) { 273 final List<Expression> exprNodes = literalNode.getElementExpressions(); 274 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprNodes.size()); 275 for (final Node node : exprNodes) { 276 if (node == null) { 277 exprTrees.add(null); 278 } else { 279 curExpr = null; 280 node.accept(this); 281 assert curExpr != null : "null for " + node; 282 exprTrees.add(curExpr); 283 } 284 } 285 curExpr = new ArrayLiteralTreeImpl(literalNode, exprTrees); 286 } else { 287 curExpr = new LiteralTreeImpl(literalNode); 288 } 289 290 return false; 291 } 292 293 @Override 294 public boolean enterObjectNode(final ObjectNode objectNode) { 295 final List<PropertyNode> propNodes = objectNode.getElements(); 296 final List<PropertyTreeImpl> propTrees = new ArrayList<>(propNodes.size()); 297 for (final PropertyNode propNode : propNodes) { 298 propTrees.add(new PropertyTreeImpl(propNode, 299 translateExpr(propNode.getKey()), 300 translateExpr(propNode.getValue()), 301 (FunctionExpressionTree) translateExpr(propNode.getGetter()), 302 (FunctionExpressionTree) translateExpr(propNode.getSetter()))); 303 } 304 curExpr = new ObjectLiteralTreeImpl(objectNode, propTrees); 305 return false; 306 } 307 308 @Override 309 public boolean enterPropertyNode(final PropertyNode propertyNode) { 310 assert false : "should not reach here!"; 311 return false; 312 } 313 314 @Override 315 public boolean enterReturnNode(final ReturnNode returnNode) { 316 curStat = new ReturnTreeImpl(returnNode, 317 translateExpr(returnNode.getExpression())); 318 return false; 319 } 320 321 @Override 322 public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 323 assert false : "should not reach here: RuntimeNode"; 324 return false; 325 } 326 327 @Override 328 public boolean enterSplitNode(final SplitNode splitNode) { 329 assert false : "should not reach here!"; 330 return false; 331 } 332 333 @Override 334 public boolean enterSwitchNode(final SwitchNode switchNode) { 335 final List<CaseNode> caseNodes = switchNode.getCases(); 336 final List<CaseTreeImpl> caseTrees = new ArrayList<>(caseNodes.size()); 337 for (final CaseNode caseNode : caseNodes) { 338 final Block body = caseNode.getBody(); 339 caseTrees.add( 340 new CaseTreeImpl(caseNode, 341 translateExpr(caseNode.getTest()), 342 translateStats(body != null? body.getStatements() : null))); 343 } 344 345 curStat = new SwitchTreeImpl(switchNode, 346 translateExpr(switchNode.getExpression()), 347 caseTrees); 348 return false; 349 } 350 351 @Override 352 public boolean enterTernaryNode(final TernaryNode ternaryNode) { 353 curExpr = new ConditionalExpressionTreeImpl(ternaryNode, 354 translateExpr(ternaryNode.getTest()), 355 translateExpr(ternaryNode.getTrueExpression()), 356 translateExpr(ternaryNode.getFalseExpression())); 357 return false; 358 } 359 360 @Override 361 public boolean enterThrowNode(final ThrowNode throwNode) { 362 curStat = new ThrowTreeImpl(throwNode, 363 translateExpr(throwNode.getExpression())); 364 return false; 365 } 366 367 @Override 368 public boolean enterTryNode(final TryNode tryNode) { 369 final List<? extends CatchNode> catchNodes = tryNode.getCatches(); 370 final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size()); 371 for (final CatchNode catchNode : catchNodes) { 372 catchTrees.add(new CatchTreeImpl(catchNode, 373 translateIdent(catchNode.getException()), 374 (BlockTree) translateBlock(catchNode.getBody()), 375 translateExpr(catchNode.getExceptionCondition()))); 376 } 377 378 curStat = new TryTreeImpl(tryNode, 379 (BlockTree) translateBlock(tryNode.getBody()), 380 catchTrees, 381 (BlockTree) translateBlock(tryNode.getFinallyBody())); 382 383 return false; 384 } 385 386 @Override 387 public boolean enterUnaryNode(final UnaryNode unaryNode) { 388 if (unaryNode.tokenType() == TokenType.NEW) { 389 curExpr = new NewTreeImpl(unaryNode, 390 translateExpr(unaryNode.getExpression())); 391 } else { 392 curExpr = new UnaryTreeImpl(unaryNode, 393 translateExpr(unaryNode.getExpression())); 394 } 395 return false; 396 } 397 398 @Override 399 public boolean enterVarNode(final VarNode varNode) { 400 final Expression initNode = varNode.getInit(); 401 if (initNode instanceof FunctionNode && ((FunctionNode)initNode).isDeclared()) { 402 final FunctionNode funcNode = (FunctionNode) initNode; 403 404 final List<? extends ExpressionTree> paramTrees 405 = translateExprs(funcNode.getParameters()); 406 final BlockTree blockTree = (BlockTree) translateBlock(funcNode.getBody(), true); 407 curStat = new FunctionDeclarationTreeImpl(varNode, paramTrees, blockTree); 408 } else { 409 curStat = new VariableTreeImpl(varNode, translateExpr(initNode)); 410 } 411 412 return false; 413 } 414 415 @Override 416 public boolean enterWhileNode(final WhileNode whileNode) { 417 final ExpressionTree condTree = translateExpr(whileNode.getTest()); 418 final StatementTree statTree = translateBlock(whileNode.getBody()); 419 420 if (whileNode.isDoWhile()) { 421 curStat = new DoWhileLoopTreeImpl(whileNode, condTree, statTree); 422 } else { 423 curStat = new WhileLoopTreeImpl(whileNode, condTree, statTree); 424 } 425 426 return false; 427 } 428 429 @Override 430 public boolean enterWithNode(final WithNode withNode) { 431 curStat = new WithTreeImpl(withNode, 432 translateExpr(withNode.getExpression()), 433 translateBlock(withNode.getBody())); 434 435 return false; 436 } 437 438 private StatementTree translateBlock(final Block blockNode) { 439 return translateBlock(blockNode, false); 440 } 441 442 private StatementTree translateBlock(final Block blockNode, final boolean sortStats) { 443 if (blockNode == null) { 444 return null; 445 } 446 curStat = null; 447 handleBlock(blockNode, sortStats); 448 return curStat; 449 } 450 451 private boolean handleBlock(final Block block, final boolean sortStats) { 452 // FIXME: revisit this! 453 if (block.isSynthetic()) { 454 final int statCount = block.getStatementCount(); 455 switch (statCount) { 456 case 0: { 457 final EmptyNode emptyNode = new EmptyNode(-1, block.getToken(), block.getFinish()); 458 curStat = new EmptyStatementTreeImpl(emptyNode); 459 return false; 460 } 461 case 1: { 462 curStat = translateStat(block.getStatements().get(0)); 463 return false; 464 } 465 default: { 466 // fall through 467 break; 468 } 469 } 470 } 471 472 final List<? extends Statement> stats = block.getStatements(); 473 curStat = new BlockTreeImpl(block, 474 translateStats(sortStats? getOrderedStatements(stats) : stats)); 475 return false; 476 } 477 478 private List<? extends Statement> getOrderedStatements(final List<? extends Statement> stats) { 479 final List<? extends Statement> statList = new ArrayList<>(stats); 480 statList.sort(Comparator.comparingInt(Node::getSourceOrder)); 481 return statList; 482 } 483 484 private List<? extends StatementTree> translateStats(final List<? extends Statement> stats) { 485 if (stats == null) { 486 return null; 487 } 488 final List<StatementTreeImpl> statTrees = new ArrayList<>(stats.size()); 489 for (final Statement stat : stats) { 490 curStat = null; 491 stat.accept(this); 492 assert curStat != null; 493 statTrees.add(curStat); 494 } 495 return statTrees; 496 } 497 498 private List<? extends ExpressionTree> translateExprs(final List<? extends Expression> exprs) { 499 if (exprs == null) { 500 return null; 501 } 502 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprs.size()); 503 for (final Expression expr : exprs) { 504 curExpr = null; 505 expr.accept(this); 506 assert curExpr != null; 507 exprTrees.add(curExpr); 508 } 509 return exprTrees; 510 } 511 512 private ExpressionTreeImpl translateExpr(final Expression expr) { 513 if (expr == null) { 514 return null; 515 } 516 517 curExpr = null; 518 expr.accept(this); 519 assert curExpr != null : "null for " + expr; 520 return curExpr; 521 } 522 523 private StatementTreeImpl translateStat(final Statement stat) { 524 if (stat == null) { 525 return null; 526 } 527 528 curStat = null; 529 stat.accept(this); 530 assert curStat != null : "null for " + stat; 531 return curStat; 532 } 533 534 private static IdentifierTree translateIdent(final IdentNode ident) { 535 return new IdentifierTreeImpl(ident); 536 } 537} 538