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