IRTranslator.java revision 1220:8bbea2def25f
1156952Sume/*
2156952Sume * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3156952Sume * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4156952Sume *
5156952Sume * This code is free software; you can redistribute it and/or modify it
6156952Sume * under the terms of the GNU General Public License version 2 only, as
7156952Sume * published by the Free Software Foundation.  Oracle designates this
8156952Sume * particular file as subject to the "Classpath" exception as provided
9156952Sume * by Oracle in the LICENSE file that accompanied this code.
10156952Sume *
11156952Sume * This code is distributed in the hope that it will be useful, but WITHOUT
12156952Sume * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13156952Sume * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14156952Sume * version 2 for more details (a copy is included in the LICENSE file that
15156952Sume * accompanied this code).
16156952Sume *
17156952Sume * You should have received a copy of the GNU General Public License version
18156952Sume * 2 along with this work; if not, write to the Free Software Foundation,
19270838Sume * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20156952Sume *
21270838Sume * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22270838Sume * or visit www.oracle.com if you need additional information or have any
23156952Sume * questions.
24156952Sume */
25156952Sumepackage jdk.nashorn.api.tree;
26156952Sume
27156952Sumeimport java.util.ArrayList;
28156952Sumeimport java.util.Comparator;
29156952Sumeimport java.util.List;
30156952Sumeimport jdk.nashorn.internal.ir.AccessNode;
31156952Sumeimport jdk.nashorn.internal.ir.BinaryNode;
32156952Sumeimport jdk.nashorn.internal.ir.Block;
33156952Sumeimport jdk.nashorn.internal.ir.BlockStatement;
34156952Sumeimport jdk.nashorn.internal.ir.BreakNode;
35156952Sumeimport jdk.nashorn.internal.ir.CallNode;
36156952Sumeimport jdk.nashorn.internal.ir.CaseNode;
37156952Sumeimport jdk.nashorn.internal.ir.CatchNode;
38156952Sumeimport jdk.nashorn.internal.ir.ContinueNode;
39156952Sumeimport jdk.nashorn.internal.ir.DebuggerNode;
40156952Sumeimport jdk.nashorn.internal.ir.EmptyNode;
41156952Sumeimport jdk.nashorn.internal.ir.ErrorNode;
42156952Sumeimport jdk.nashorn.internal.ir.Expression;
43156952Sumeimport jdk.nashorn.internal.ir.ExpressionStatement;
44156952Sumeimport jdk.nashorn.internal.ir.ForNode;
45165254Sumeimport jdk.nashorn.internal.ir.FunctionNode;
46165254Sumeimport jdk.nashorn.internal.ir.IdentNode;
47165254Sumeimport jdk.nashorn.internal.ir.IfNode;
48165254Sumeimport jdk.nashorn.internal.ir.IndexNode;
49156952Sumeimport jdk.nashorn.internal.ir.LabelNode;
50170242Sumeimport jdk.nashorn.internal.ir.LexicalContext;
51156952Sumeimport jdk.nashorn.internal.ir.LiteralNode;
52156952Sumeimport jdk.nashorn.internal.ir.Node;
53156952Sumeimport jdk.nashorn.internal.ir.ObjectNode;
54156952Sumeimport jdk.nashorn.internal.ir.PropertyNode;
55156952Sumeimport jdk.nashorn.internal.ir.ReturnNode;
56156952Sumeimport jdk.nashorn.internal.ir.RuntimeNode;
57156952Sumeimport jdk.nashorn.internal.ir.SplitNode;
58156952Sumeimport jdk.nashorn.internal.ir.Statement;
59156952Sumeimport jdk.nashorn.internal.ir.SwitchNode;
60156952Sumeimport jdk.nashorn.internal.ir.TernaryNode;
61156952Sumeimport jdk.nashorn.internal.ir.ThrowNode;
62156952Sumeimport jdk.nashorn.internal.ir.TryNode;
63156952Sumeimport jdk.nashorn.internal.ir.UnaryNode;
64156952Sumeimport jdk.nashorn.internal.ir.VarNode;
65156952Sumeimport jdk.nashorn.internal.ir.WhileNode;
66156952Sumeimport jdk.nashorn.internal.ir.WithNode;
67156952Sumeimport jdk.nashorn.internal.ir.visitor.NodeVisitor;
68156952Sumeimport jdk.nashorn.internal.parser.Lexer;
69156952Sumeimport jdk.nashorn.internal.parser.TokenType;
70156952Sume
71156952Sume/**
72156952Sume * This class translates from nashorn IR Node objects
73156952Sume * to nashorn parser API Tree objects.
74156952Sume */
75156952Sumefinal class IRTranslator extends NodeVisitor<LexicalContext> {
76156952Sume
77156952Sume    public IRTranslator() {
78156952Sume        super(new LexicalContext());
79156952Sume    }
80156952Sume
81156952Sume    // currently translated Statement
82156952Sume    private StatementTreeImpl curStat;
83156952Sume    // currently translated Expression
84156952Sume    private ExpressionTreeImpl curExpr;
85156952Sume
86156952Sume    // entry point for translator
87156952Sume    CompilationUnitTree translate(final FunctionNode node) {
88156952Sume        if (node == null) {
89156952Sume            return null;
90156952Sume        }
91156952Sume
92156952Sume        assert (node.getKind() == FunctionNode.Kind.SCRIPT) : "script function expected";
93156952Sume
94156952Sume        final Block body = node.getBody();
95156952Sume        return new CompilationUnitTreeImpl(node,
96156952Sume                translateStats(body != null? getOrderedStatements(body.getStatements()) : null));
97170242Sume    }
98156952Sume
99156952Sume    @Override
100156952Sume    public boolean enterAccessNode(final AccessNode accessNode) {
101156952Sume        curExpr = new MemberSelectTreeImpl(accessNode, translateExpr(accessNode.getBase()));
102156952Sume        return false;
103156952Sume    }
104156952Sume
105156952Sume    @Override
106156952Sume    public boolean enterBlock(final Block block) {
107156952Sume        return handleBlock(block, false);
108156952Sume    }
109156952Sume
110156952Sume    @Override
111156952Sume    public boolean enterBinaryNode(final BinaryNode binaryNode) {
112156952Sume        if (binaryNode.isAssignment()) {
113156952Sume            final ExpressionTree srcTree = translateExpr(binaryNode.getAssignmentSource());
114156952Sume            final ExpressionTree destTree = translateExpr(binaryNode.getAssignmentDest());
115156952Sume
116156952Sume            if (binaryNode.tokenType() == TokenType.ASSIGN) {
117156952Sume                curExpr = new AssignmentTreeImpl(binaryNode, destTree, srcTree);
118156952Sume            } else {
119156952Sume                curExpr = new CompoundAssignmentTreeImpl(binaryNode, destTree, srcTree);
120156952Sume            }
121156952Sume        } else {
122156952Sume            final ExpressionTree leftTree = translateExpr(binaryNode.lhs());
123156952Sume            final ExpressionTree rightTree = translateExpr(binaryNode.rhs());
124156952Sume
125156952Sume            if (binaryNode.tokenType() == TokenType.INSTANCEOF) {
126156952Sume                curExpr = new InstanceOfTreeImpl(binaryNode, leftTree, rightTree);
127156952Sume            } else {
128156952Sume                curExpr = new BinaryTreeImpl(binaryNode, leftTree, rightTree);
129156952Sume            }
130156952Sume        }
131156952Sume
132156952Sume        return false;
133156952Sume    }
134156952Sume
135156952Sume    @Override
136156952Sume    public boolean enterBreakNode(final BreakNode breakNode) {
137156952Sume        curStat = new BreakTreeImpl(breakNode);
138156952Sume        return false;
139156952Sume    }
140156952Sume
141156952Sume    @Override
142156952Sume    public boolean enterCallNode(final CallNode callNode) {
143156952Sume        curExpr = null;
144156952Sume        callNode.getFunction().accept(this);
145156952Sume        final ExpressionTree funcTree = curExpr;
146156952Sume        final List<? extends ExpressionTree> argTrees = translateExprs(callNode.getArgs());
147156952Sume        curExpr = new FunctionCallTreeImpl(callNode, funcTree, argTrees);
148156952Sume        return false;
149156952Sume    }
150156952Sume
151156952Sume    @Override
152156952Sume    public boolean enterCaseNode(final CaseNode caseNode) {
153156952Sume        assert false : "should not reach here!";
154156952Sume        return false;
155156952Sume    }
156156952Sume
157156952Sume    @Override
158156952Sume    public boolean enterCatchNode(final CatchNode catchNode) {
159156952Sume        assert false : "should not reach here";
160156952Sume        return false;
161156952Sume    }
162156952Sume
163156952Sume    @Override
164156952Sume    public boolean enterContinueNode(final ContinueNode continueNode) {
165156952Sume        curStat = new ContinueTreeImpl(continueNode);
166156952Sume        return false;
167156952Sume    }
168156952Sume
169156952Sume    @Override
170156952Sume    public boolean enterDebuggerNode(final DebuggerNode debuggerNode) {
171156952Sume        curStat = new DebuggerTreeImpl(debuggerNode);
172156952Sume        return false;
173156952Sume    }
174156952Sume
175156952Sume    @Override
176156952Sume    public boolean enterEmptyNode(final EmptyNode emptyNode) {
177156952Sume        curStat = new EmptyStatementTreeImpl(emptyNode);
178156952Sume        return false;
179156952Sume    }
180156952Sume
181156952Sume    @Override
182156952Sume    public boolean enterErrorNode(final ErrorNode errorNode) {
183156952Sume        curExpr = new ErroneousTreeImpl(errorNode);
184156952Sume        return false;
185156952Sume    }
186156952Sume
187156952Sume    @Override
188156952Sume    public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
189156952Sume        curStat = new ExpressionStatementTreeImpl(expressionStatement,
190156952Sume                translateExpr(expressionStatement.getExpression()));
191156952Sume        return false;
192156952Sume    }
193156952Sume
194156952Sume    @Override
195156952Sume    public boolean enterBlockStatement(final BlockStatement blockStatement) {
196156952Sume        final Block block = blockStatement.getBlock();
197156952Sume        if (blockStatement.isSynthetic()) {
198156952Sume            assert block != null && block.getStatements() != null && block.getStatements().size() == 1;
199156952Sume            curStat = translateStat(block.getStatements().get(0));
200156952Sume        } else {
201156952Sume            curStat = new BlockTreeImpl(blockStatement,
202156952Sume                translateStats(block != null? block.getStatements() : null));
203156952Sume        }
204156952Sume        return false;
205156952Sume    }
206156952Sume
207156952Sume    @Override
208156952Sume    public boolean enterForNode(final ForNode forNode) {
209156952Sume        if (forNode.isForIn()) {
210156952Sume            curStat = new ForInLoopTreeImpl(forNode,
211156952Sume                    translateExpr(forNode.getInit()),
212156952Sume                    translateExpr(forNode.getModify()),
213156952Sume                    translateBlock(forNode.getBody()));
214156952Sume        } else {
215156952Sume            curStat = new ForLoopTreeImpl(forNode,
216156952Sume                    translateExpr(forNode.getInit()),
217156952Sume                    translateExpr(forNode.getTest()),
218156952Sume                    translateExpr(forNode.getModify()),
219156952Sume                    translateBlock(forNode.getBody()));
220156952Sume        }
221156952Sume
222156952Sume        return false;
223156952Sume    }
224156952Sume
225156952Sume    @Override
226156952Sume    public boolean enterFunctionNode(final FunctionNode functionNode) {
227156952Sume        assert !functionNode.isDeclared() : "should not reach here for function declaration";
228156952Sume
229156952Sume        final List<? extends ExpressionTree> paramTrees
230156952Sume                    = translateExprs(functionNode.getParameters());
231156952Sume        final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody(), true);
232156952Sume        curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree);
233156952Sume
234156952Sume        return false;
235156952Sume    }
236156952Sume
237156952Sume    @Override
238156952Sume    public boolean enterIdentNode(final IdentNode identNode) {
239156952Sume        curExpr = new IdentifierTreeImpl(identNode);
240156952Sume        return false;
241156952Sume    }
242156952Sume
243156952Sume    @Override
244156952Sume    public boolean enterIfNode(final IfNode ifNode) {
245156952Sume        curStat = new IfTreeImpl(ifNode,
246156952Sume                translateExpr(ifNode.getTest()),
247156952Sume                translateBlock(ifNode.getPass()),
248156952Sume                translateBlock(ifNode.getFail()));
249156952Sume        return false;
250156952Sume    }
251156952Sume
252156952Sume    @Override
253156952Sume    public boolean enterIndexNode(final IndexNode indexNode) {
254156952Sume        curExpr = new ArrayAccessTreeImpl(indexNode,
255156952Sume                translateExpr(indexNode.getBase()),
256156952Sume                translateExpr(indexNode.getIndex()));
257156952Sume        return false;
258156952Sume    }
259156952Sume
260156952Sume    @Override
261156952Sume    public boolean enterLabelNode(final LabelNode labelNode) {
262156952Sume        curStat = new LabeledStatementTreeImpl(labelNode,
263156952Sume                translateBlock(labelNode.getBody()));
264170242Sume        return false;
265170242Sume    }
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