1 /* 2 * Copyright (c) 1998, 2007, 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 26 /* 27 * Licensed Materials - Property of IBM 28 * RMI-IIOP v1.0 29 * Copyright IBM Corp. 1998 1999 All Rights Reserved 30 * 31 */ 32 33 package sun.rmi.rmic.iiop; 34 35 import sun.tools.java.CompilerError; 36 37 /** 38 * ContextStack provides a mechanism to record parsing state. 39 * 40 * @author Bryan Atsatt 41 */ 42 public class ContextStack { 43 44 // Context codes. 45 46 public static final int TOP = 1; 47 48 public static final int METHOD = 2; 49 public static final int METHOD_RETURN = 3; 50 public static final int METHOD_ARGUMENT = 4; 51 public static final int METHOD_EXCEPTION = 5; 52 53 public static final int MEMBER = 6; 54 public static final int MEMBER_CONSTANT = 7; 55 public static final int MEMBER_STATIC = 8; 56 public static final int MEMBER_TRANSIENT = 9; 57 58 public static final int IMPLEMENTS = 10; 59 public static final int EXTENDS = 11; 60 61 // String versions of context codes. 62 63 private static final String[] CODE_NAMES = { 64 "UNKNOWN ", 65 "Top level type ", 66 "Method ", 67 "Return parameter ", 68 "Parameter ", 69 "Exception ", 70 "Member ", 71 "Constant member ", 72 "Static member ", 73 "Transient member ", 74 "Implements ", 75 "Extends ", 76 }; 77 // Member data. 78 79 private int currentIndex = -1; 80 private int maxIndex = 100; 81 private TypeContext[] stack = new TypeContext[maxIndex]; 82 private int newCode = TOP; 83 private BatchEnvironment env = null; 84 private boolean trace = false; 85 private TypeContext tempContext = new TypeContext(); 86 87 private static final String TRACE_INDENT = " "; 88 89 /** 90 * Constructor. 91 */ 92 public ContextStack (BatchEnvironment env) { 93 this.env = env; 94 env.contextStack = this; 95 } 96 97 /** 98 * Return true if {@code env.nerrors > 0}. 99 */ 100 public boolean anyErrors () { 101 return env.nerrors > 0; 102 } 103 104 /** 105 * Enable/disable tracing. 106 */ 107 public void setTrace(boolean trace) { 108 this.trace = trace; 109 } 110 111 /** 112 * Check trace flag. 113 */ 114 public boolean isTraceOn() { 115 return trace; 116 } 117 118 /** 119 * Get the environment. 120 */ 121 public BatchEnvironment getEnv() { 122 return env; 123 } 124 125 /** 126 * Set the new context. 127 */ 128 public void setNewContextCode(int code) { 129 newCode = code; 130 } 131 132 /** 133 * Get the current context code. 134 */ 135 public int getCurrentContextCode() { 136 return newCode; 137 } 138 139 140 /** 141 * If tracing on, write the current call stack (not the context stack) to 142 * System.out. 143 */ 144 final void traceCallStack () { 145 if (trace) dumpCallStack(); 146 } 147 148 public final static void dumpCallStack() { 149 new Error().printStackTrace(System.out); 150 } 151 152 /** 153 * Print a line indented by stack depth. 154 */ 155 final private void tracePrint (String text, boolean line) { 156 int length = text.length() + (currentIndex * TRACE_INDENT.length()); 157 StringBuffer buffer = new StringBuffer(length); 158 for (int i = 0; i < currentIndex; i++) { 159 buffer.append(TRACE_INDENT); 160 } 161 buffer.append(text); 162 if (line) { 163 buffer.append("\n"); 164 } 165 System.out.print(buffer.toString()); 166 } 167 168 /** 169 * If tracing on, print a line. 170 */ 171 final void trace (String text) { 172 if (trace) { 173 tracePrint(text,false); 174 } 175 } 176 177 /** 178 * If tracing on, print a line followed by a '\n'. 179 */ 180 final void traceln (String text) { 181 if (trace) { 182 tracePrint(text,true); 183 } 184 } 185 186 /** 187 * If tracing on, print a pre-mapped ContextElement. 188 */ 189 final void traceExistingType (Type type) { 190 if (trace) { 191 tempContext.set(newCode,type); 192 traceln(toResultString(tempContext,true,true)); 193 } 194 } 195 196 /** 197 * Push a new element on the stack. 198 * @return the new element. 199 */ 200 public TypeContext push (ContextElement element) { 201 202 currentIndex++; 203 204 // Grow array if need to... 205 206 if (currentIndex == maxIndex) { 207 int newMax = maxIndex * 2; 208 TypeContext[] newStack = new TypeContext[newMax]; 209 System.arraycopy(stack,0,newStack,0,maxIndex); 210 maxIndex = newMax; 211 stack = newStack; 212 } 213 214 // Make sure we have a context object to use at this position... 215 216 TypeContext it = stack[currentIndex]; 217 218 if (it == null) { 219 it = new TypeContext(); 220 stack[currentIndex] = it; 221 } 222 223 // Set the context object... 224 225 it.set(newCode,element); 226 227 // Trace... 228 229 traceln(toTrialString(it)); 230 231 // Return... 232 233 return it; 234 } 235 236 /** 237 * Pop an element from the stack. 238 * @return the new current element or null if top. 239 */ 240 public TypeContext pop (boolean wasValid) { 241 242 if (currentIndex < 0) { 243 throw new CompilerError("Nothing on stack!"); 244 } 245 246 newCode = stack[currentIndex].getCode(); 247 traceln(toResultString(stack[currentIndex],wasValid,false)); 248 249 Type last = stack[currentIndex].getCandidateType(); 250 if (last != null) { 251 252 // Set status... 253 254 if (wasValid) { 255 last.setStatus(Constants.STATUS_VALID); 256 } else { 257 last.setStatus(Constants.STATUS_INVALID); 258 } 259 } 260 261 currentIndex--; 262 263 if (currentIndex < 0) { 264 265 // Done parsing, so update the invalid types 266 // if this type was valid... 267 268 if (wasValid) { 269 Type.updateAllInvalidTypes(this); 270 } 271 return null; 272 } else { 273 return stack[currentIndex]; 274 } 275 } 276 277 /** 278 * Get the current size. 279 */ 280 public int size () { 281 return currentIndex + 1; 282 } 283 284 /** 285 * Get a specific context. 286 */ 287 public TypeContext getContext (int index) { 288 289 if (currentIndex < index) { 290 throw new Error("Index out of range"); 291 } 292 return stack[index]; 293 } 294 295 /** 296 * Get the current top context. 297 */ 298 public TypeContext getContext () { 299 300 if (currentIndex < 0) { 301 throw new Error("Nothing on stack!"); 302 } 303 return stack[currentIndex]; 304 } 305 306 /** 307 * Is parent context a value type? 308 */ 309 public boolean isParentAValue () { 310 311 if (currentIndex > 0) { 312 return stack[currentIndex - 1].isValue(); 313 } else { 314 return false; 315 } 316 } 317 318 /** 319 * Get parent context. Null if none. 320 */ 321 public TypeContext getParentContext () { 322 323 if (currentIndex > 0) { 324 return stack[currentIndex - 1]; 325 } else { 326 return null; 327 } 328 } 329 330 /** 331 * Get a string for the context name... 332 */ 333 public String getContextCodeString () { 334 335 if (currentIndex >= 0) { 336 return CODE_NAMES[newCode]; 337 } else { 338 return CODE_NAMES[0]; 339 } 340 } 341 342 /** 343 * Get a string for the given context code... 344 */ 345 public static String getContextCodeString (int contextCode) { 346 return CODE_NAMES[contextCode]; 347 } 348 349 private String toTrialString(TypeContext it) { 350 int code = it.getCode(); 351 if (code != METHOD && code != MEMBER) { 352 return it.toString() + " (trying " + it.getTypeDescription() + ")"; 353 } else { 354 return it.toString(); 355 } 356 } 357 358 private String toResultString (TypeContext it, boolean result, boolean preExisting) { 359 int code = it.getCode(); 360 if (code != METHOD && code != MEMBER) { 361 if (result) { 362 String str = it.toString() + " --> " + it.getTypeDescription(); 363 if (preExisting) { 364 return str + " [Previously mapped]"; 365 } else { 366 return str; 367 } 368 } 369 } else { 370 if (result) { 371 return it.toString() + " --> [Mapped]"; 372 } 373 } 374 return it.toString() + " [Did not map]"; 375 } 376 377 public void clear () { 378 for (int i = 0; i < stack.length; i++) { 379 if (stack[i] != null) stack[i].destroy(); 380 } 381 } 382 } 383 384 385 class TypeContext { 386 387 public void set(int code, ContextElement element) { 388 this.code = code; 389 this.element = element; 390 if (element instanceof ValueType) { 391 isValue = true; 392 } else { 393 isValue = false; 394 } 395 } 396 397 public int getCode() { 398 return code; 399 } 400 401 public String getName() { 402 return element.getElementName(); 403 } 404 405 public Type getCandidateType() { 406 if (element instanceof Type) { 407 return (Type) element; 408 } else { 409 return null; 410 } 411 } 412 413 public String getTypeDescription() { 414 if (element instanceof Type) { 415 return ((Type) element).getTypeDescription(); 416 } else { 417 return "[unknown type]"; 418 } 419 } 420 421 public String toString () { 422 if (element != null) { 423 return ContextStack.getContextCodeString(code) + element.getElementName(); 424 } else { 425 return ContextStack.getContextCodeString(code) + "null"; 426 } 427 } 428 429 public boolean isValue () { 430 return isValue; 431 } 432 433 public boolean isConstant () { 434 return code == ContextStack.MEMBER_CONSTANT; 435 } 436 437 public void destroy() { 438 if (element instanceof Type) { 439 ((Type)element).destroy(); 440 } 441 element = null; 442 } 443 444 private int code = 0; 445 private ContextElement element = null; 446 private boolean isValue = false; 447 }