001: /*****************************************************************************
002: * *
003: * This file is part of the BeanShell Java Scripting distribution. *
004: * Documentation and updates may be found at http://www.beanshell.org/ *
005: * *
006: * Sun Public License Notice: *
007: * *
008: * The contents of this file are subject to the Sun Public License Version *
009: * 1.0 (the "License"); you may not use this file except in compliance with *
010: * the License. A copy of the License is available at http://www.sun.com *
011: * *
012: * The Original Code is BeanShell. The Initial Developer of the Original *
013: * Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright *
014: * (C) 2000. All Rights Reserved. *
015: * *
016: * GNU Public License Notice: *
017: * *
018: * Alternatively, the contents of this file may be used under the terms of *
019: * the GNU Lesser General Public License (the "LGPL"), in which case the *
020: * provisions of LGPL are applicable instead of those above. If you wish to *
021: * allow use of your version of this file only under the terms of the LGPL *
022: * and not to allow others to use your version of this file under the SPL, *
023: * indicate your decision by deleting the provisions above and replace *
024: * them with the notice and other provisions required by the LGPL. If you *
025: * do not delete the provisions above, a recipient may use your version of *
026: * this file under either the SPL or the LGPL. *
027: * *
028: * Patrick Niemeyer (pat@pat.net) *
029: * Author of Learning Java, O'Reilly & Associates *
030: * http://www.pat.net/~pat/ *
031: * *
032: *****************************************************************************/package bsh;
033:
034: import java.lang.reflect.Array;
035:
036: class BSHType extends SimpleNode implements BshClassManager.Listener {
037: /**
038: baseType is used during evaluation of full type and retained for the
039: case where we are an array type.
040: In the case where we are not an array this will be the same as type.
041: */
042: private Class baseType;
043: /**
044: If we are an array type this will be non zero and indicate the
045: dimensionality of the array. e.g. 2 for String[][];
046: */
047: private int arrayDims;
048:
049: /**
050: Internal cache of the type. Cleared on classloader change.
051: */
052: private Class type;
053:
054: String descriptor;
055:
056: BSHType(int id) {
057: super (id);
058: }
059:
060: /**
061: Used by the grammar to indicate dimensions of array types
062: during parsing.
063: */
064: public void addArrayDimension() {
065: arrayDims++;
066: }
067:
068: SimpleNode getTypeNode() {
069: return (SimpleNode) jjtGetChild(0);
070: }
071:
072: /**
073: Returns a class descriptor for this type.
074: If the type is an ambiguous name (object type) evaluation is
075: attempted through the namespace in order to resolve imports.
076: If it is not found and the name is non-compound we assume the default
077: package for the name.
078: */
079: public String getTypeDescriptor(CallStack callstack,
080: Interpreter interpreter, String defaultPackage) {
081: // return cached type if available
082: if (descriptor != null)
083: return descriptor;
084:
085: String descriptor;
086: // first node will either be PrimitiveType or AmbiguousName
087: SimpleNode node = getTypeNode();
088: if (node instanceof BSHPrimitiveType)
089: descriptor = getTypeDescriptor(((BSHPrimitiveType) node).type);
090: else {
091: String clasName = ((BSHAmbiguousName) node).text;
092: BshClassManager bcm = interpreter.getClassManager();
093: // Note: incorrect here - we are using the hack in bsh class
094: // manager that allows lookup by base name. We need to eliminate
095: // this limitation by working through imports. See notes in class
096: // manager.
097: String definingClass = bcm.getClassBeingDefined(clasName);
098:
099: Class clas = null;
100: if (definingClass == null) {
101: try {
102: clas = ((BSHAmbiguousName) node).toClass(callstack,
103: interpreter);
104: } catch (EvalError e) {
105: //throw new InterpreterError("unable to resolve type: "+e);
106: // ignore and try default package
107: //System.out.println("BSHType: "+node+" class not found");
108: }
109: } else
110: clasName = definingClass;
111:
112: if (clas != null) {
113: //System.out.println("found clas: "+clas);
114: descriptor = getTypeDescriptor(clas);
115: } else {
116: if (defaultPackage == null || Name.isCompound(clasName))
117: descriptor = "L" + clasName.replace('.', '/') + ";";
118: else
119: descriptor = "L" + defaultPackage.replace('.', '/')
120: + "/" + clasName + ";";
121: }
122: }
123:
124: for (int i = 0; i < arrayDims; i++)
125: descriptor = "[" + descriptor;
126:
127: this .descriptor = descriptor;
128: //System.out.println("BSHType: returning descriptor: "+descriptor);
129: return descriptor;
130: }
131:
132: public Class getType(CallStack callstack, Interpreter interpreter)
133: throws EvalError {
134: // return cached type if available
135: if (type != null)
136: return type;
137:
138: // first node will either be PrimitiveType or AmbiguousName
139: SimpleNode node = getTypeNode();
140: if (node instanceof BSHPrimitiveType)
141: baseType = ((BSHPrimitiveType) node).getType();
142: else
143: baseType = ((BSHAmbiguousName) node).toClass(callstack,
144: interpreter);
145:
146: if (arrayDims > 0) {
147: try {
148: // Get the type by constructing a prototype array with
149: // arbitrary (zero) length in each dimension.
150: int[] dims = new int[arrayDims]; // int array default zeros
151: Object obj = Array.newInstance(baseType, dims);
152: type = obj.getClass();
153: } catch (Exception e) {
154: throw new EvalError("Couldn't construct array type",
155: this , callstack);
156: }
157: } else
158: type = baseType;
159:
160: // hack... sticking to first interpreter that resolves this
161: // see comments on type instance variable
162: interpreter.getClassManager().addListener(this );
163:
164: return type;
165: }
166:
167: /**
168: baseType is used during evaluation of full type and retained for the
169: case where we are an array type.
170: In the case where we are not an array this will be the same as type.
171: */
172: public Class getBaseType() {
173: return baseType;
174: }
175:
176: /**
177: If we are an array type this will be non zero and indicate the
178: dimensionality of the array. e.g. 2 for String[][];
179: */
180: public int getArrayDims() {
181: return arrayDims;
182: }
183:
184: public void classLoaderChanged() {
185: type = null;
186: baseType = null;
187: }
188:
189: public static String getTypeDescriptor(Class clas) {
190: if (clas == Boolean.TYPE)
191: return "Z";
192: if (clas == Character.TYPE)
193: return "C";
194: if (clas == Byte.TYPE)
195: return "B";
196: if (clas == Short.TYPE)
197: return "S";
198: if (clas == Integer.TYPE)
199: return "I";
200: if (clas == Long.TYPE)
201: return "J";
202: if (clas == Float.TYPE)
203: return "F";
204: if (clas == Double.TYPE)
205: return "D";
206: if (clas == Void.TYPE)
207: return "V";
208: // Is getName() ok? test with 1.1
209: String name = clas.getName().replace('.', '/');
210:
211: if (name.startsWith("[") || name.endsWith(";"))
212: return name;
213: else
214: return "L" + name.replace('.', '/') + ";";
215: }
216: }
|