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