Node.java revision 971:c93b6091b11e
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 java.util.ArrayList; 29import java.util.List; 30import jdk.nashorn.internal.ir.visitor.NodeVisitor; 31import jdk.nashorn.internal.parser.Token; 32import jdk.nashorn.internal.parser.TokenType; 33 34/** 35 * Nodes are used to compose Abstract Syntax Trees. 36 */ 37public abstract class Node implements Cloneable { 38 /** Start of source range. */ 39 protected final int start; 40 41 /** End of source range. */ 42 protected int finish; 43 44 /** Token descriptor. */ 45 private final long token; 46 47 /** 48 * Constructor 49 * 50 * @param token token 51 * @param finish finish 52 */ 53 public Node(final long token, final int finish) { 54 this.token = token; 55 this.start = Token.descPosition(token); 56 this.finish = finish; 57 } 58 59 /** 60 * Constructor 61 * 62 * @param token token 63 * @param start start 64 * @param finish finish 65 */ 66 protected Node(final long token, final int start, final int finish) { 67 this.start = start; 68 this.finish = finish; 69 this.token = token; 70 } 71 72 /** 73 * Copy constructor 74 * 75 * @param node source node 76 */ 77 protected Node(final Node node) { 78 this.token = node.token; 79 this.start = node.start; 80 this.finish = node.finish; 81 } 82 83 /** 84 * Is this a loop node? 85 * 86 * @return true if atom 87 */ 88 public boolean isLoop() { 89 return false; 90 } 91 92 /** 93 * Is this an assignment node - for example a var node with an init 94 * or a binary node that writes to a destination 95 * 96 * @return true if assignment 97 */ 98 public boolean isAssignment() { 99 return false; 100 } 101 102 /** 103 * For reference copies - ensure that labels in the copy node are unique 104 * using an appropriate copy constructor 105 * @param lc lexical context 106 * @return new node or same of no labels 107 */ 108 public Node ensureUniqueLabels(final LexicalContext lc) { 109 return this; 110 } 111 112 /** 113 * Provides a means to navigate the IR. 114 * @param visitor Node visitor. 115 * @return node the node or its replacement after visitation, null if no further visitations are required 116 */ 117 public abstract Node accept(NodeVisitor<? extends LexicalContext> visitor); 118 119 @Override 120 public String toString() { 121 final StringBuilder sb = new StringBuilder(); 122 toString(sb); 123 return sb.toString(); 124 } 125 126 /** 127 * String conversion helper. Fills a {@link StringBuilder} with the 128 * string version of this node 129 * 130 * @param sb a StringBuilder 131 */ 132 public void toString(final StringBuilder sb) { 133 toString(sb, true); 134 } 135 136 /** 137 * Print logic that decides whether to show the optimistic type 138 * or not - for example it should not be printed after just parse, 139 * when it hasn't been computed, or has been set to a trivially provable 140 * value 141 * @param sb string builder 142 * @param printType print type? 143 */ 144 public abstract void toString(final StringBuilder sb, final boolean printType); 145 146 /** 147 * Get the finish position for this node in the source string 148 * @return finish 149 */ 150 public int getFinish() { 151 return finish; 152 } 153 154 /** 155 * Set finish position for this node in the source string 156 * @param finish finish 157 */ 158 public void setFinish(final int finish) { 159 this.finish = finish; 160 } 161 162 /** 163 * Get start position for node 164 * @return start position 165 */ 166 public int getStart() { 167 return start; 168 } 169 170 @Override 171 protected Object clone() { 172 try { 173 return super.clone(); 174 } catch (final CloneNotSupportedException e) { 175 throw new AssertionError(e); 176 } 177 } 178 179 @Override 180 public final boolean equals(final Object other) { 181 return super.equals(other); 182 } 183 184 @Override 185 public final int hashCode() { 186 return super.hashCode(); 187 } 188 189 /** 190 * Return token position from a token descriptor. 191 * 192 * @return Start position of the token in the source. 193 */ 194 public int position() { 195 return Token.descPosition(token); 196 } 197 198 /** 199 * Return token length from a token descriptor. 200 * 201 * @return Length of the token. 202 */ 203 public int length() { 204 return Token.descLength(token); 205 } 206 207 /** 208 * Return token tokenType from a token descriptor. 209 * 210 * @return Type of token. 211 */ 212 public TokenType tokenType() { 213 return Token.descType(token); 214 } 215 216 /** 217 * Test token tokenType. 218 * 219 * @param type a type to check this token against 220 * @return true if token types match. 221 */ 222 public boolean isTokenType(final TokenType type) { 223 return Token.descType(token) == type; 224 } 225 226 /** 227 * Get the token for this location 228 * @return the token 229 */ 230 public long getToken() { 231 return token; 232 } 233 234 //on change, we have to replace the entire list, that's we can't simple do ListIterator.set 235 static <T extends Node> List<T> accept(final NodeVisitor<? extends LexicalContext> visitor, final List<T> list) { 236 final int size = list.size(); 237 if (size == 0) { 238 return list; 239 } 240 241 List<T> newList = null; 242 243 for (int i = 0; i < size; i++) { 244 final T node = list.get(i); 245 @SuppressWarnings("unchecked") 246 final T newNode = node == null ? null : (T)node.accept(visitor); 247 if (newNode != node) { 248 if (newList == null) { 249 newList = new ArrayList<>(size); 250 for (int j = 0; j < i; j++) { 251 newList.add(list.get(j)); 252 } 253 } 254 newList.add(newNode); 255 } else { 256 if (newList != null) { 257 newList.add(node); 258 } 259 } 260 } 261 262 return newList == null ? list : newList; 263 } 264 265 static <T extends LexicalContextNode> T replaceInLexicalContext(final LexicalContext lc, final T oldNode, final T newNode) { 266 if (lc != null) { 267 lc.replace(oldNode, newNode); 268 } 269 return newNode; 270 } 271} 272