/* * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * Licensed Materials - Property of IBM * RMI-IIOP v1.0 * Copyright IBM Corp. 1998 1999 All Rights Reserved * */ package sun.rmi.rmic.iiop; import sun.tools.java.CompilerError; /** * ContextStack provides a mechanism to record parsing state. * * @author Bryan Atsatt */ public class ContextStack { // Context codes. public static final int TOP = 1; public static final int METHOD = 2; public static final int METHOD_RETURN = 3; public static final int METHOD_ARGUMENT = 4; public static final int METHOD_EXCEPTION = 5; public static final int MEMBER = 6; public static final int MEMBER_CONSTANT = 7; public static final int MEMBER_STATIC = 8; public static final int MEMBER_TRANSIENT = 9; public static final int IMPLEMENTS = 10; public static final int EXTENDS = 11; // String versions of context codes. private static final String[] CODE_NAMES = { "UNKNOWN ", "Top level type ", "Method ", "Return parameter ", "Parameter ", "Exception ", "Member ", "Constant member ", "Static member ", "Transient member ", "Implements ", "Extends ", }; // Member data. private int currentIndex = -1; private int maxIndex = 100; private TypeContext[] stack = new TypeContext[maxIndex]; private int newCode = TOP; private BatchEnvironment env = null; private boolean trace = false; private TypeContext tempContext = new TypeContext(); private static final String TRACE_INDENT = " "; /** * Constructor. */ public ContextStack (BatchEnvironment env) { this.env = env; env.contextStack = this; } /** * Return true if env.nerrors > 0. */ public boolean anyErrors () { return env.nerrors > 0; } /** * Enable/disable tracing. */ public void setTrace(boolean trace) { this.trace = trace; } /** * Check trace flag. */ public boolean isTraceOn() { return trace; } /** * Get the environment. */ public BatchEnvironment getEnv() { return env; } /** * Set the new context. */ public void setNewContextCode(int code) { newCode = code; } /** * Get the current context code. */ public int getCurrentContextCode() { return newCode; } /** * If tracing on, write the current call stack (not the context stack) to * System.out. */ final void traceCallStack () { if (trace) dumpCallStack(); } public final static void dumpCallStack() { new Error().printStackTrace(System.out); } /** * Print a line indented by stack depth. */ final private void tracePrint (String text, boolean line) { int length = text.length() + (currentIndex * TRACE_INDENT.length()); StringBuffer buffer = new StringBuffer(length); for (int i = 0; i < currentIndex; i++) { buffer.append(TRACE_INDENT); } buffer.append(text); if (line) { buffer.append("\n"); } System.out.print(buffer.toString()); } /** * If tracing on, print a line. */ final void trace (String text) { if (trace) { tracePrint(text,false); } } /** * If tracing on, print a line followed by a '\n'. */ final void traceln (String text) { if (trace) { tracePrint(text,true); } } /** * If tracing on, print a pre-mapped ContextElement. */ final void traceExistingType (Type type) { if (trace) { tempContext.set(newCode,type); traceln(toResultString(tempContext,true,true)); } } /** * Push a new element on the stack. * @return the new element. */ public TypeContext push (ContextElement element) { currentIndex++; // Grow array if need to... if (currentIndex == maxIndex) { int newMax = maxIndex * 2; TypeContext[] newStack = new TypeContext[newMax]; System.arraycopy(stack,0,newStack,0,maxIndex); maxIndex = newMax; stack = newStack; } // Make sure we have a context object to use at this position... TypeContext it = stack[currentIndex]; if (it == null) { it = new TypeContext(); stack[currentIndex] = it; } // Set the context object... it.set(newCode,element); // Trace... traceln(toTrialString(it)); // Return... return it; } /** * Pop an element from the stack. * @return the new current element or null if top. */ public TypeContext pop (boolean wasValid) { if (currentIndex < 0) { throw new CompilerError("Nothing on stack!"); } newCode = stack[currentIndex].getCode(); traceln(toResultString(stack[currentIndex],wasValid,false)); Type last = stack[currentIndex].getCandidateType(); if (last != null) { // Set status... if (wasValid) { last.setStatus(Constants.STATUS_VALID); } else { last.setStatus(Constants.STATUS_INVALID); } } currentIndex--; if (currentIndex < 0) { // Done parsing, so update the invalid types // if this type was valid... if (wasValid) { Type.updateAllInvalidTypes(this); } return null; } else { return stack[currentIndex]; } } /** * Get the current size. */ public int size () { return currentIndex + 1; } /** * Get a specific context. */ public TypeContext getContext (int index) { if (currentIndex < index) { throw new Error("Index out of range"); } return stack[index]; } /** * Get the current top context. */ public TypeContext getContext () { if (currentIndex < 0) { throw new Error("Nothing on stack!"); } return stack[currentIndex]; } /** * Is parent context a value type? */ public boolean isParentAValue () { if (currentIndex > 0) { return stack[currentIndex - 1].isValue(); } else { return false; } } /** * Get parent context. Null if none. */ public TypeContext getParentContext () { if (currentIndex > 0) { return stack[currentIndex - 1]; } else { return null; } } /** * Get a string for the context name... */ public String getContextCodeString () { if (currentIndex >= 0) { return CODE_NAMES[newCode]; } else { return CODE_NAMES[0]; } } /** * Get a string for the given context code... */ public static String getContextCodeString (int contextCode) { return CODE_NAMES[contextCode]; } private String toTrialString(TypeContext it) { int code = it.getCode(); if (code != METHOD && code != MEMBER) { return it.toString() + " (trying " + it.getTypeDescription() + ")"; } else { return it.toString(); } } private String toResultString (TypeContext it, boolean result, boolean preExisting) { int code = it.getCode(); if (code != METHOD && code != MEMBER) { if (result) { String str = it.toString() + " --> " + it.getTypeDescription(); if (preExisting) { return str + " [Previously mapped]"; } else { return str; } } } else { if (result) { return it.toString() + " --> [Mapped]"; } } return it.toString() + " [Did not map]"; } public void clear () { for (int i = 0; i < stack.length; i++) { if (stack[i] != null) stack[i].destroy(); } } } class TypeContext { public void set(int code, ContextElement element) { this.code = code; this.element = element; if (element instanceof ValueType) { isValue = true; } else { isValue = false; } } public int getCode() { return code; } public String getName() { return element.getElementName(); } public Type getCandidateType() { if (element instanceof Type) { return (Type) element; } else { return null; } } public String getTypeDescription() { if (element instanceof Type) { return ((Type) element).getTypeDescription(); } else { return "[unknown type]"; } } public String toString () { if (element != null) { return ContextStack.getContextCodeString(code) + element.getElementName(); } else { return ContextStack.getContextCodeString(code) + "null"; } } public boolean isValue () { return isValue; } public boolean isConstant () { return code == ContextStack.MEMBER_CONSTANT; } public void destroy() { if (element instanceof Type) { ((Type)element).destroy(); } element = null; } private int code = 0; private ContextElement element = null; private boolean isValue = false; }