Node.java revision 953:221a84ef44c0
1169691Skan/*
2169691Skan * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3169691Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169691Skan *
5169691Skan * This code is free software; you can redistribute it and/or modify it
6169691Skan * under the terms of the GNU General Public License version 2 only, as
7169691Skan * published by the Free Software Foundation.  Oracle designates this
8169691Skan * particular file as subject to the "Classpath" exception as provided
9169691Skan * by Oracle in the LICENSE file that accompanied this code.
10169691Skan *
11169691Skan * This code is distributed in the hope that it will be useful, but WITHOUT
12169691Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13169691Skan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14169691Skan * version 2 for more details (a copy is included in the LICENSE file that
15169691Skan * accompanied this code).
16169691Skan *
17169691Skan * You should have received a copy of the GNU General Public License version
18169691Skan * 2 along with this work; if not, write to the Free Software Foundation,
19169691Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20169691Skan *
21169691Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22169691Skan * or visit www.oracle.com if you need additional information or have any
23169691Skan * questions.
24169691Skan */
25169691Skan
26169691Skanpackage jdk.nashorn.internal.ir;
27169691Skan
28169691Skanimport java.util.ArrayList;
29169691Skanimport java.util.List;
30169691Skan
31169691Skanimport jdk.nashorn.internal.ir.visitor.NodeVisitor;
32169691Skanimport jdk.nashorn.internal.parser.Token;
33169691Skanimport jdk.nashorn.internal.parser.TokenType;
34169691Skan
35169691Skan/**
36169691Skan * Nodes are used to compose Abstract Syntax Trees.
37169691Skan */
38169691Skanpublic abstract class Node implements Cloneable {
39169691Skan    /** Start of source range. */
40169691Skan    protected final int start;
41169691Skan
42169691Skan    /** End of source range. */
43169691Skan    protected int finish;
44169691Skan
45169691Skan    /** Token descriptor. */
46169691Skan    private final long token;
47169691Skan
48169691Skan    /**
49169691Skan     * Constructor
50169691Skan     *
51169691Skan     * @param token  token
52169691Skan     * @param finish finish
53169691Skan     */
54169691Skan    public Node(final long token, final int finish) {
55169691Skan        this.token  = token;
56169691Skan        this.start  = Token.descPosition(token);
57169691Skan        this.finish = finish;
58169691Skan    }
59169691Skan
60169691Skan    /**
61169691Skan     * Constructor
62169691Skan     *
63169691Skan     * @param token   token
64169691Skan     * @param start   start
65169691Skan     * @param finish  finish
66169691Skan     */
67169691Skan    protected Node(final long token, final int start, final int finish) {
68169691Skan        this.start = start;
69169691Skan        this.finish = finish;
70169691Skan        this.token = token;
71169691Skan    }
72169691Skan
73169691Skan    /**
74169691Skan     * Copy constructor
75169691Skan     *
76169691Skan     * @param node source node
77169691Skan     */
78169691Skan    protected Node(final Node node) {
79169691Skan        this.token  = node.token;
80169691Skan        this.start  = node.start;
81169691Skan        this.finish = node.finish;
82169691Skan    }
83169691Skan
84169691Skan    /**
85169691Skan     * Is this a loop node?
86     *
87     * @return true if atom
88     */
89    public boolean isLoop() {
90        return false;
91    }
92
93    /**
94     * Is this an assignment node - for example a var node with an init
95     * or a binary node that writes to a destination
96     *
97     * @return true if assignment
98     */
99    public boolean isAssignment() {
100        return false;
101    }
102
103    /**
104     * For reference copies - ensure that labels in the copy node are unique
105     * using an appropriate copy constructor
106     * @param lc lexical context
107     * @return new node or same of no labels
108     */
109    public Node ensureUniqueLabels(final LexicalContext lc) {
110        return this;
111    }
112
113    /**
114     * Provides a means to navigate the IR.
115     * @param visitor Node visitor.
116     * @return node the node or its replacement after visitation, null if no further visitations are required
117     */
118    public abstract Node accept(NodeVisitor<? extends LexicalContext> visitor);
119
120    @Override
121    public String toString() {
122        final StringBuilder sb = new StringBuilder();
123        toString(sb);
124        return sb.toString();
125    }
126
127    /**
128     * String conversion helper. Fills a {@link StringBuilder} with the
129     * string version of this node
130     *
131     * @param sb a StringBuilder
132     */
133    public void toString(final StringBuilder sb) {
134        toString(sb, true);
135    }
136
137    /**
138     * Print logic that decides whether to show the optimistic type
139     * or not - for example it should not be printed after just parse,
140     * when it hasn't been computed, or has been set to a trivially provable
141     * value
142     * @param sb   string builder
143     * @param printType print type?
144     */
145    public abstract void toString(final StringBuilder sb, final boolean printType);
146
147    /**
148     * Get the finish position for this node in the source string
149     * @return finish
150     */
151    public int getFinish() {
152        return finish;
153    }
154
155    /**
156     * Set finish position for this node in the source string
157     * @param finish finish
158     */
159    public void setFinish(final int finish) {
160        this.finish = finish;
161    }
162
163    /**
164     * Get start position for node
165     * @return start position
166     */
167    public int getStart() {
168        return start;
169    }
170
171    @Override
172    protected Object clone() {
173        try {
174            return super.clone();
175        } catch (final CloneNotSupportedException e) {
176            throw new AssertionError(e);
177        }
178    }
179
180    @Override
181    public final boolean equals(final Object other) {
182        return super.equals(other);
183    }
184
185    @Override
186    public final int hashCode() {
187        return super.hashCode();
188    }
189
190    /**
191     * Return token position from a token descriptor.
192     *
193     * @return Start position of the token in the source.
194     */
195    public int position() {
196        return Token.descPosition(token);
197    }
198
199    /**
200     * Return token length from a token descriptor.
201     *
202     * @return Length of the token.
203     */
204    public int length() {
205        return Token.descLength(token);
206    }
207
208    /**
209     * Return token tokenType from a token descriptor.
210     *
211     * @return Type of token.
212     */
213    public TokenType tokenType() {
214        return Token.descType(token);
215    }
216
217    /**
218     * Test token tokenType.
219     *
220     * @param type a type to check this token against
221     * @return true if token types match.
222     */
223    public boolean isTokenType(final TokenType type) {
224        return Token.descType(token) == type;
225    }
226
227    /**
228     * Get the token for this location
229     * @return the token
230     */
231    public long getToken() {
232        return token;
233    }
234
235    //on change, we have to replace the entire list, that's we can't simple do ListIterator.set
236    static <T extends Node> List<T> accept(final NodeVisitor<? extends LexicalContext> visitor, final List<T> list) {
237        final int size = list.size();
238        if (size == 0) {
239            return list;
240        }
241
242         List<T> newList = null;
243
244        for (int i = 0; i < size; i++) {
245            final T node = list.get(i);
246            @SuppressWarnings("unchecked")
247            final T newNode = node == null ? null : (T)node.accept(visitor);
248            if (newNode != node) {
249                if (newList == null) {
250                    newList = new ArrayList<>(size);
251                    for (int j = 0; j < i; j++) {
252                        newList.add(list.get(j));
253                    }
254                }
255                newList.add(newNode);
256            } else {
257                if (newList != null) {
258                    newList.add(node);
259                }
260            }
261        }
262
263        return newList == null ? list : newList;
264    }
265
266    static <T extends LexicalContextNode> T replaceInLexicalContext(final LexicalContext lc, final T oldNode, final T newNode) {
267        if (lc != null) {
268            lc.replace(oldNode, newNode);
269        }
270        return newNode;
271    }
272}
273