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.codegen.Label;
29
30/**
31 * Common base class for jump statements (e.g. {@code break} and {@code continue}).
32 */
33public abstract class JumpStatement extends Statement implements JoinPredecessor {
34    private static final long serialVersionUID = 1L;
35
36    private final String labelName;
37    private final LocalVariableConversion conversion;
38
39    /**
40     * Constructor
41     *
42     * @param lineNumber line number
43     * @param token      token
44     * @param finish     finish
45     * @param labelName  label name for break or null if none
46     */
47    protected JumpStatement(final int lineNumber, final long token, final int finish, final String labelName) {
48        super(lineNumber, token, finish);
49        this.labelName = labelName;
50        this.conversion = null;
51    }
52
53    /**
54     * Copy constructor.
55     * @param jumpStatement the original jump statement.
56     * @param conversion a new local variable conversion.
57     */
58    protected JumpStatement(final JumpStatement jumpStatement, final LocalVariableConversion conversion) {
59        super(jumpStatement);
60        this.labelName = jumpStatement.labelName;
61        this.conversion = conversion;
62    }
63
64    @Override
65    public boolean hasGoto() {
66        return true;
67    }
68
69    /**
70     * Get the label name for this break node
71     * @return label name, or null if none
72     */
73    public String getLabelName() {
74        return labelName;
75    }
76
77    @Override
78    public void toString(final StringBuilder sb, final boolean printType) {
79        sb.append(getStatementName());
80
81        if (labelName != null) {
82            sb.append(' ').append(labelName);
83        }
84    }
85
86    abstract String getStatementName();
87
88    /**
89     * Finds the target for this jump statement in a lexical context.
90     * @param lc the lexical context
91     * @return the target, or null if not found
92     */
93    public abstract BreakableNode getTarget(final LexicalContext lc);
94
95    /**
96     * Returns the label corresponding to this kind of jump statement (either a break or continue label) in the target.
97     * @param target the target. Note that it need not be the target of this jump statement, as the method can retrieve
98     * a label on any passed target as long as the target has a label of the requisite kind. Of course, it is advisable
99     * to invoke the method on a jump statement that targets the breakable.
100     * @return the label of the target corresponding to the kind of jump statement.
101     * @throws ClassCastException if invoked on the kind of breakable node that this jump statement is not prepared to
102     * handle.
103     */
104    abstract Label getTargetLabel(final BreakableNode target);
105
106    /**
107     * Returns the label this jump statement targets.
108     * @param lc the lexical context
109     * @return the label this jump statement targets.
110     */
111    public Label getTargetLabel(final LexicalContext lc) {
112        return getTargetLabel(getTarget(lc));
113    }
114
115    /**
116     * Returns the limit node for popping scopes when this jump statement is effected.
117     * @param lc the current lexical context
118     * @return the limit node for popping scopes when this jump statement is effected.
119     */
120    public LexicalContextNode getPopScopeLimit(final LexicalContext lc) {
121        // In most cases (break and continue) this is equal to the target.
122        return getTarget(lc);
123    }
124
125    @Override
126    public JumpStatement setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) {
127        if(this.conversion == conversion) {
128            return this;
129        }
130        return createNewJumpStatement(conversion);
131    }
132
133    abstract JumpStatement createNewJumpStatement(LocalVariableConversion newConversion);
134
135    @Override
136    public LocalVariableConversion getLocalVariableConversion() {
137        return conversion;
138    }
139}
140