ContextStack.java revision 673:6b017d166ac2
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
33package sun.rmi.rmic.iiop;
34
35import sun.tools.java.CompilerError;
36
37/**
38 * ContextStack provides a mechanism to record parsing state.
39 *
40 * @author      Bryan Atsatt
41 */
42public 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
385class 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
413public String getTypeDescription() {
414    if (element instanceof Type) {
415        return ((Type) element).getTypeDescription();
416    } else {
417        return "[unknown type]";
418    }
419}
420
421public String toString () {
422    if (element != null) {
423        return ContextStack.getContextCodeString(code) + element.getElementName();
424    } else {
425        return ContextStack.getContextCodeString(code) + "null";
426    }
427}
428
429public 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}
448