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 final List<Statement> statNodes = block.getStatements(); 107 // FIXME: revisit this! 108 curStat = new BlockTreeImpl(block, translateStats(statNodes)); 109 return false; 110 } 111 112 @Override 113 public boolean enterBinaryNode(final BinaryNode binaryNode) { 114 if (binaryNode.isAssignment()) { 115 final ExpressionTree srcTree = translateExpr(binaryNode.getAssignmentSource()); 116 final ExpressionTree destTree = translateExpr(binaryNode.getAssignmentDest()); 117 118 if (binaryNode.tokenType() == TokenType.ASSIGN) { 119 curExpr = new AssignmentTreeImpl(binaryNode, destTree, srcTree); 120 } else { 121 curExpr = new CompoundAssignmentTreeImpl(binaryNode, destTree, srcTree); 122 } 123 } else { 124 final ExpressionTree leftTree = translateExpr(binaryNode.lhs()); 125 final ExpressionTree rightTree = translateExpr(binaryNode.rhs()); 126 127 if (binaryNode.tokenType() == TokenType.INSTANCEOF) { 128 curExpr = new InstanceOfTreeImpl(binaryNode, leftTree, rightTree); 129 } else { 130 curExpr = new BinaryTreeImpl(binaryNode, leftTree, rightTree); 131 } 132 } 133 134 return false; 135 } 136 137 @Override 138 public boolean enterBreakNode(final BreakNode breakNode) { 139 curStat = new BreakTreeImpl(breakNode); 140 return false; 141 } 142 143 @Override 144 public boolean enterCallNode(final CallNode callNode) { 145 curExpr = null; 146 callNode.getFunction().accept(this); 147 final ExpressionTree funcTree = curExpr; 148 final List<? extends ExpressionTree> argTrees = translateExprs(callNode.getArgs()); 149 curExpr = new FunctionCallTreeImpl(callNode, funcTree, argTrees); 150 return false; 151 } 152 153 @Override 154 public boolean enterCaseNode(final CaseNode caseNode) { 155 assert false : "should not reach here!"; 156 return false; 157 } 158 159 @Override 160 public boolean enterCatchNode(final CatchNode catchNode) { 161 assert false : "should not reach here"; 162 return false; 163 } 164 165 @Override 166 public boolean enterContinueNode(final ContinueNode continueNode) { 167 curStat = new ContinueTreeImpl(continueNode); 168 return false; 169 } 170 171 @Override 172 public boolean enterDebuggerNode(final DebuggerNode debuggerNode) { 173 curStat = new DebuggerTreeImpl(debuggerNode); 174 return false; 175 } 176 177 @Override 178 public boolean enterEmptyNode(final EmptyNode emptyNode) { 179 curStat = new EmptyStatementTreeImpl(emptyNode); 180 return false; 181 } 182 183 @Override 184 public boolean enterErrorNode(final ErrorNode errorNode) { 185 curExpr = new ErroneousTreeImpl(errorNode); 186 return false; 187 } 188 189 @Override 190 public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { 191 curStat = new ExpressionStatementTreeImpl(expressionStatement, 192 translateExpr(expressionStatement.getExpression())); 193 return false; 194 } 195 196 @Override 197 public boolean enterBlockStatement(final BlockStatement blockStatement) { 198 final Block block = blockStatement.getBlock(); 199 if (blockStatement.isSynthetic()) { 200 assert block != null && block.getStatements() != null && block.getStatements().size() == 1; 201 curStat = translateStat(block.getStatements().get(0)); 202 } else { 203 curStat = new BlockTreeImpl(blockStatement, 204 translateStats(block != null? block.getStatements() : null)); 205 } 206 return false; 207 } 208 209 @Override 210 public boolean enterForNode(final ForNode forNode) { 211 if (forNode.isForIn()) { 212 curStat = new ForInLoopTreeImpl(forNode, 213 translateExpr(forNode.getInit()), 214 translateExpr(forNode.getModify()), 215 translateBlock(forNode.getBody())); 216 } else { 217 curStat = new ForLoopTreeImpl(forNode, 218 translateExpr(forNode.getInit()), 219 translateExpr(forNode.getTest()), 220 translateExpr(forNode.getModify()), 221 translateBlock(forNode.getBody())); 222 } 223 224 return false; 225 } 226 227 @Override 228 public boolean enterFunctionNode(final FunctionNode functionNode) { 229 assert !functionNode.isDeclared() : "should not reach here for function declaration"; 230 231 final List<? extends ExpressionTree> paramTrees 232 = translateExprs(functionNode.getParameters()); 233 final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody()); 234 curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree); 235 236 return false; 237 } 238 239 @Override 240 public boolean enterIdentNode(final IdentNode identNode) { 241 curExpr = new IdentifierTreeImpl(identNode); 242 return false; 243 } 244 245 @Override 246 public boolean enterIfNode(final IfNode ifNode) { 247 curStat = new IfTreeImpl(ifNode, 248 translateExpr(ifNode.getTest()), 249 translateBlock(ifNode.getPass()), 250 translateBlock(ifNode.getFail())); 251 return false; 252 } 253 254 @Override 255 public boolean enterIndexNode(final IndexNode indexNode) { 256 curExpr = new ArrayAccessTreeImpl(indexNode, 257 translateExpr(indexNode.getBase()), 258 translateExpr(indexNode.getIndex())); 259 return false; 260 } 261 262 @Override 263 public boolean enterLabelNode(final LabelNode labelNode) { 264 curStat = new LabeledStatementTreeImpl(labelNode, 265 translateBlock(labelNode.getBody())); 266 return false; 267 } 268 269 @Override 270 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 271 final Object value = literalNode.getValue(); 272 if (value instanceof Lexer.RegexToken) { 273 curExpr = new RegExpLiteralTreeImpl(literalNode); 274 } else if (literalNode.isArray()) { 275 final List<Expression> exprNodes = literalNode.getElementExpressions(); 276 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprNodes.size()); 277 for (final Node node : exprNodes) { 278 if (node == null) { 279 exprTrees.add(null); 280 } else { 281 curExpr = null; 282 node.accept(this); 283 assert curExpr != null : "null for " + node; 284 exprTrees.add(curExpr); 285 } 286 } 287 curExpr = new ArrayLiteralTreeImpl(literalNode, exprTrees); 288 } else { 289 curExpr = new LiteralTreeImpl(literalNode); 290 } 291 292 return false; 293 } 294 295 @Override 296 public boolean enterObjectNode(final ObjectNode objectNode) { 297 final List<PropertyNode> propNodes = objectNode.getElements(); 298 final List<PropertyTreeImpl> propTrees = new ArrayList<>(propNodes.size()); 299 for (final PropertyNode propNode : propNodes) { 300 propTrees.add(new PropertyTreeImpl(propNode, 301 translateExpr(propNode.getKey()), 302 translateExpr(propNode.getValue()), 303 (FunctionExpressionTree) translateExpr(propNode.getGetter()), 304 (FunctionExpressionTree) translateExpr(propNode.getSetter()))); 305 } 306 curExpr = new ObjectLiteralTreeImpl(objectNode, propTrees); 307 return false; 308 } 309 310 @Override 311 public boolean enterPropertyNode(final PropertyNode propertyNode) { 312 assert false : "should not reach here!"; 313 return false; 314 } 315 316 @Override 317 public boolean enterReturnNode(final ReturnNode returnNode) { 318 curStat = new ReturnTreeImpl(returnNode, 319 translateExpr(returnNode.getExpression())); 320 return false; 321 } 322 323 @Override 324 public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 325 assert false : "should not reach here: RuntimeNode"; 326 return false; 327 } 328 329 @Override 330 public boolean enterSplitNode(final SplitNode splitNode) { 331 assert false : "should not reach here!"; 332 return false; 333 } 334 335 @Override 336 public boolean enterSwitchNode(final SwitchNode switchNode) { 337 final List<CaseNode> caseNodes = switchNode.getCases(); 338 final List<CaseTreeImpl> caseTrees = new ArrayList<>(caseNodes.size()); 339 for (final CaseNode caseNode : caseNodes) { 340 final Block body = caseNode.getBody(); 341 caseTrees.add( 342 new CaseTreeImpl(caseNode, 343 translateExpr(caseNode.getTest()), 344 translateStats(body != null? body.getStatements() : null))); 345 } 346 347 curStat = new SwitchTreeImpl(switchNode, 348 translateExpr(switchNode.getExpression()), 349 caseTrees); 350 return false; 351 } 352 353 @Override 354 public boolean enterTernaryNode(final TernaryNode ternaryNode) { 355 curExpr = new ConditionalExpressionTreeImpl(ternaryNode, 356 translateExpr(ternaryNode.getTest()), 357 translateExpr(ternaryNode.getTrueExpression()), 358 translateExpr(ternaryNode.getFalseExpression())); 359 return false; 360 } 361 362 @Override 363 public boolean enterThrowNode(final ThrowNode throwNode) { 364 curStat = new ThrowTreeImpl(throwNode, 365 translateExpr(throwNode.getExpression())); 366 return false; 367 } 368 369 @Override 370 public boolean enterTryNode(final TryNode tryNode) { 371 final List<? extends CatchNode> catchNodes = tryNode.getCatches(); 372 final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size()); 373 for (final CatchNode catchNode : catchNodes) { 374 catchTrees.add(new CatchTreeImpl(catchNode, 375 translateIdent(catchNode.getException()), 376 (BlockTree) translateBlock(catchNode.getBody()), 377 translateExpr(catchNode.getExceptionCondition()))); 378 } 379 380 curStat = new TryTreeImpl(tryNode, 381 (BlockTree) translateBlock(tryNode.getBody()), 382 catchTrees, 383 (BlockTree) translateBlock(tryNode.getFinallyBody())); 384 385 return false; 386 } 387 388 @Override 389 public boolean enterUnaryNode(final UnaryNode unaryNode) { 390 if (unaryNode.tokenType() == TokenType.NEW) { 391 curExpr = new NewTreeImpl(unaryNode, 392 translateExpr(unaryNode.getExpression())); 393 } else { 394 curExpr = new UnaryTreeImpl(unaryNode, 395 translateExpr(unaryNode.getExpression())); 396 } 397 return false; 398 } 399 400 @Override 401 public boolean enterVarNode(final VarNode varNode) { 402 final Expression initNode = varNode.getInit(); 403 if (initNode instanceof FunctionNode && ((FunctionNode)initNode).isDeclared()) { 404 final FunctionNode funcNode = (FunctionNode) initNode; 405 406 final List<? extends ExpressionTree> paramTrees 407 = translateExprs(funcNode.getParameters()); 408 final BlockTree blockTree = (BlockTree) translateBlock(funcNode.getBody()); 409 curStat = new FunctionDeclarationTreeImpl(varNode, paramTrees, blockTree); 410 } else { 411 curStat = new VariableTreeImpl(varNode, translateExpr(initNode)); 412 } 413 414 return false; 415 } 416 417 @Override 418 public boolean enterWhileNode(final WhileNode whileNode) { 419 final ExpressionTree condTree = translateExpr(whileNode.getTest()); 420 final StatementTree statTree = translateBlock(whileNode.getBody()); 421 422 if (whileNode.isDoWhile()) { 423 curStat = new DoWhileLoopTreeImpl(whileNode, condTree, statTree); 424 } else { 425 curStat = new WhileLoopTreeImpl(whileNode, condTree, statTree); 426 } 427 428 return false; 429 } 430 431 @Override 432 public boolean enterWithNode(final WithNode withNode) { 433 curStat = new WithTreeImpl(withNode, 434 translateExpr(withNode.getExpression()), 435 translateBlock(withNode.getBody())); 436 437 return false; 438 } 439 440 private StatementTree translateBlock(final Block blockNode) { 441 if (blockNode == null) { 442 return null; 443 } 444 curStat = null; 445 blockNode.accept(this); 446 return curStat; 447 } 448 449 private List<? extends StatementTree> translateStats(final List<? extends Statement> stats) { 450 if (stats == null) { 451 return null; 452 } 453 final List<StatementTreeImpl> statTrees = new ArrayList<>(stats.size()); 454 for (final Statement stat : stats) { 455 curStat = null; 456 stat.accept(this); 457 assert curStat != null; 458 statTrees.add(curStat); 459 } 460 return statTrees; 461 } 462 463 private List<? extends ExpressionTree> translateExprs(final List<? extends Expression> exprs) { 464 if (exprs == null) { 465 return null; 466 } 467 final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprs.size()); 468 for (final Expression expr : exprs) { 469 curExpr = null; 470 expr.accept(this); 471 assert curExpr != null; 472 exprTrees.add(curExpr); 473 } 474 return exprTrees; 475 } 476 477 private ExpressionTreeImpl translateExpr(final Expression expr) { 478 if (expr == null) { 479 return null; 480 } 481 482 curExpr = null; 483 expr.accept(this); 484 assert curExpr != null : "null for " + expr; 485 return curExpr; 486 } 487 488 private StatementTreeImpl translateStat(final Statement stat) { 489 if (stat == null) { 490 return null; 491 } 492 493 curStat = null; 494 stat.accept(this); 495 assert curStat != null : "null for " + stat; 496 return curStat; 497 } 498 499 private IdentifierTree translateIdent(final IdentNode ident) { 500 return new IdentifierTreeImpl(ident); 501 } 502 }