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