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 }