1/*
2 * Copyright (c) 2010, 2013, 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
26package jdk.nashorn.internal.ir;
27
28import jdk.nashorn.internal.ir.annotations.Immutable;
29import jdk.nashorn.internal.ir.visitor.NodeVisitor;
30
31/**
32 * IR representation for an IF statement.
33 */
34@Immutable
35public final class IfNode extends Statement implements JoinPredecessor {
36    private static final long serialVersionUID = 1L;
37
38    /** Test expression. */
39    private final Expression test;
40
41    /** Pass statements. */
42    private final Block pass;
43
44    /** Fail statements. */
45    private final Block fail;
46
47    /**
48     * Local variable conversions that need to be performed after test if it evaluates to false, and there's no else
49     * branch.
50     */
51    private final LocalVariableConversion conversion;
52
53    /**
54     * Constructor
55     *
56     * @param lineNumber line number
57     * @param token      token
58     * @param finish     finish
59     * @param test       test
60     * @param pass       block to execute when test passes
61     * @param fail       block to execute when test fails or null
62     */
63    public IfNode(final int lineNumber, final long token, final int finish, final Expression test, final Block pass, final Block fail) {
64        super(lineNumber, token, finish);
65        this.test = test;
66        this.pass = pass;
67        this.fail = fail;
68        this.conversion = null;
69    }
70
71    private IfNode(final IfNode ifNode, final Expression test, final Block pass, final Block fail, final LocalVariableConversion conversion) {
72        super(ifNode);
73        this.test = test;
74        this.pass = pass;
75        this.fail = fail;
76        this.conversion = conversion;
77    }
78
79    @Override
80    public boolean isTerminal() {
81        return pass.isTerminal() && fail != null && fail.isTerminal();
82    }
83
84    @Override
85    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
86        if (visitor.enterIfNode(this)) {
87            return visitor.leaveIfNode(
88                setTest((Expression)test.accept(visitor)).
89                setPass((Block)pass.accept(visitor)).
90                setFail(fail == null ? null : (Block)fail.accept(visitor)));
91        }
92
93        return this;
94    }
95
96    @Override
97    public void toString(final StringBuilder sb, final boolean printTypes) {
98        sb.append("if (");
99        test.toString(sb, printTypes);
100        sb.append(')');
101    }
102
103    /**
104     * Get the else block of this IfNode
105     * @return the else block, or null if none exists
106     */
107    public Block getFail() {
108        return fail;
109    }
110
111    private IfNode setFail(final Block fail) {
112        if (this.fail == fail) {
113            return this;
114        }
115        return new IfNode(this, test, pass, fail, conversion);
116    }
117
118    /**
119     * Get the then block for this IfNode
120     * @return the then block
121     */
122    public Block getPass() {
123        return pass;
124    }
125
126    private IfNode setPass(final Block pass) {
127        if (this.pass == pass) {
128            return this;
129        }
130        return new IfNode(this, test, pass, fail, conversion);
131    }
132
133    /**
134     * Get the test expression for this IfNode
135     * @return the test expression
136     */
137    public Expression getTest() {
138        return test;
139    }
140
141    /**
142     * Reset the test expression for this IfNode
143     * @param test a new test expression
144     * @return new or same IfNode
145     */
146    public IfNode setTest(final Expression test) {
147        if (this.test == test) {
148            return this;
149        }
150        return new IfNode(this, test, pass, fail, conversion);
151    }
152
153    @Override
154    public IfNode setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) {
155        if(this.conversion == conversion) {
156            return this;
157        }
158        return new IfNode(this, test, pass, fail, conversion);
159    }
160
161    @Override
162    public LocalVariableConversion getLocalVariableConversion() {
163        return conversion;
164    }
165}
166