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.Comparator;
29 import java.util.List;
30 import jdk.nashorn.internal.ir.AccessNode;
31 import jdk.nashorn.internal.ir.BinaryNode;
32 import jdk.nashorn.internal.ir.Block;
33 import jdk.nashorn.internal.ir.BlockStatement;
34 import jdk.nashorn.internal.ir.BreakNode;
35 import jdk.nashorn.internal.ir.CallNode;
36 import jdk.nashorn.internal.ir.CaseNode;
37 import jdk.nashorn.internal.ir.CatchNode;
38 import jdk.nashorn.internal.ir.ContinueNode;
39 import jdk.nashorn.internal.ir.DebuggerNode;
40 import jdk.nashorn.internal.ir.EmptyNode;
41 import jdk.nashorn.internal.ir.ErrorNode;
42 import jdk.nashorn.internal.ir.Expression;
43 import jdk.nashorn.internal.ir.ExpressionStatement;
44 import jdk.nashorn.internal.ir.ForNode;
45 import jdk.nashorn.internal.ir.FunctionNode;
46 import jdk.nashorn.internal.ir.IdentNode;
47 import jdk.nashorn.internal.ir.IfNode;
48 import jdk.nashorn.internal.ir.IndexNode;
49 import jdk.nashorn.internal.ir.LabelNode;
50 import jdk.nashorn.internal.ir.LexicalContext;
51 import jdk.nashorn.internal.ir.LiteralNode;
52 import jdk.nashorn.internal.ir.Node;
53 import jdk.nashorn.internal.ir.ObjectNode;
54 import jdk.nashorn.internal.ir.PropertyNode;
55 import jdk.nashorn.internal.ir.ReturnNode;
56 import jdk.nashorn.internal.ir.RuntimeNode;
57 import jdk.nashorn.internal.ir.SplitNode;
58 import jdk.nashorn.internal.ir.Statement;
59 import jdk.nashorn.internal.ir.SwitchNode;
60 import jdk.nashorn.internal.ir.TernaryNode;
61 import jdk.nashorn.internal.ir.ThrowNode;
62 import jdk.nashorn.internal.ir.TryNode;
63 import jdk.nashorn.internal.ir.UnaryNode;
64 import jdk.nashorn.internal.ir.VarNode;
65 import jdk.nashorn.internal.ir.WhileNode;
66 import jdk.nashorn.internal.ir.WithNode;
67 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
68 import jdk.nashorn.internal.parser.Lexer;
69 import jdk.nashorn.internal.parser.TokenType;
70
71 /**
72 * This class translates from nashorn IR Node objects
73 * to nashorn parser API Tree objects.
74 */
75 final class IRTranslator extends NodeVisitor<LexicalContext> {
76
77 public IRTranslator() {
78 super(new LexicalContext());
79 }
80
81 // currently translated Statement
82 private StatementTreeImpl curStat;
83 // currently translated Expression
84 private ExpressionTreeImpl curExpr;
85
86 // entry point for translator
87 CompilationUnitTree translate(final FunctionNode node) {
88 if (node == null) {
89 return null;
90 }
91
92 assert (node.getKind() == FunctionNode.Kind.SCRIPT) : "script function expected";
93
94 final Block body = node.getBody();
95 return new CompilationUnitTreeImpl(node,
96 translateStats(body != null? getOrderedStatements(body.getStatements()) : null));
97 }
98
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.isTokenType(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.isTokenType(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.isTokenType(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 }
--- EOF ---