001: /*
002: * JavaNewCmd.java --
003: *
004: * Implements the built-in "java::new" command.
005: *
006: * Copyright (c) 1997 Sun Microsystems, Inc. All rights reserved.
007: *
008: * See the file "license.terms" for information on usage and
009: * redistribution of this file, and for a DISCLAIMER OF ALL
010: * WARRANTIES.
011: *
012: * RCS: @(#) $Id: JavaNewCmd.java,v 1.6 2006/04/13 07:36:50 mdejong Exp $
013: *
014: */
015:
016: package tcl.lang;
017:
018: import tcl.lang.reflect.PkgInvoker;
019:
020: /*
021: * This class implements the built-in "java::new" command.
022: */
023:
024: class JavaNewCmd implements Command {
025:
026: /*
027: *----------------------------------------------------------------------
028: *
029: * cmdProc --
030: *
031: * This procedure is invoked to process the "java::new" Tcl
032: * comamnd. See the user documentation for details on what
033: * it does.
034: *
035: * Results:
036: * None.
037: *
038: * Side effects:
039: * A standard Tcl result is stored in the interpreter.
040: *
041: *----------------------------------------------------------------------
042: */
043:
044: public void cmdProc(Interp interp, // Current interpreter.
045: TclObject argv[]) // Argument list.
046: throws TclException // A standard Tcl exception.
047: {
048: if (argv.length < 2) {
049: throw new TclNumArgsException(interp, 1, argv,
050: "signature ?arg arg ...?");
051: }
052:
053: // The "java::new" command can take both array signatures and
054: // constructor signatures. We want to know what type of signature
055: // is given without throwing and catching exceptions. Thus, we
056: // call ArraySig.looksLikeArraySig() to determine quickly whether
057: // a argv[1] can be interpreted as an array signature or a
058: // constructor signature. This is a much less expensive way than
059: // calling ArraySig.get() and then calling JavaInvoke.newInstance()
060: // if that fails.
061:
062: if (ArraySig.looksLikeArraySig(interp, argv[1])) {
063: // Create a new Java array object.
064:
065: if ((argv.length < 3) || (argv.length > 4)) {
066: throw new TclNumArgsException(interp, 2, argv,
067: "sizeList ?valueList?");
068: }
069:
070: ArraySig sig = ArraySig.get(interp, argv[1]);
071: Class arrayType = sig.arrayType;
072: int dimensions = sig.dimensions;
073:
074: TclObject sizeListObj = argv[2];
075: int sizeListLen = TclList.getLength(interp, sizeListObj);
076:
077: if (sizeListLen > dimensions) {
078: throw new TclException(interp, "size list \""
079: + sizeListObj
080: + "\" doesn't match array dimension ("
081: + dimensions + ")");
082: }
083:
084: TclObject valueListObj = null;
085: if (argv.length == 4) {
086: valueListObj = argv[3];
087: }
088:
089: // Initialize arrayObj according to dimensions of both
090: // sizeListObj and valueListObj.
091:
092: Object obj = ArrayObject
093: .initArray(interp, sizeListObj, sizeListLen, 0,
094: dimensions, arrayType, valueListObj);
095:
096: interp.setResult(ReflectObject.newInstance(interp,
097: arrayType, obj));
098: } else {
099: // Create a new (scalar) Java object.
100:
101: int startIdx = 2;
102: int count = argv.length - startIdx;
103:
104: interp.setResult(JavaInvoke.newInstance(interp, argv[1],
105: argv, startIdx, count));
106: }
107: }
108:
109: } // end JavaNewCmd
110:
111: // The ArraySig class is used internally by the JavaNewCmd
112: // class. ArraySig implements a new Tcl object type that represents an
113: // array signature used for creating Java arrays. Examples or array
114: // signatures are "int[][]", "java.lang.Object[]" or "[[D".
115:
116: class ArraySig implements InternalRep {
117:
118: // The Class object for the array (for example int[][][])
119: Class arrayType;
120:
121: // The number of dimensions specified by the signature. For example,
122: // int[][][] has a dimension of 3.
123:
124: int dimensions;
125:
126: /*
127: *----------------------------------------------------------------------
128: *
129: * ArraySig --
130: *
131: * Creates a new ArraySig instance.
132: *
133: * Side effects:
134: * Member fields are initialized.
135: *
136: *----------------------------------------------------------------------
137: */
138:
139: ArraySig(Class type, // Initial value for arrayType.
140: int n) // Initial value for dimensions.
141: {
142: arrayType = type;
143: dimensions = n;
144: }
145:
146: /*
147: *----------------------------------------------------------------------
148: *
149: * duplicate --
150: *
151: * Make a copy of an object's internal representation.
152: *
153: * Results:
154: * Returns a newly allocated instance of the appropriate type.
155: *
156: * Side effects:
157: * None.
158: *
159: *----------------------------------------------------------------------
160: */
161:
162: public InternalRep duplicate() {
163: return new ArraySig(arrayType, dimensions);
164: }
165:
166: /**
167: * Implement this no-op for the InternalRep interface.
168: */
169:
170: public void dispose() {
171: }
172:
173: /*
174: *----------------------------------------------------------------------
175: *
176: * looksLikeArraySig --
177: *
178: * This method quickly determines whether a TclObject can be
179: * interpreted as an array signature or a constructor signature.
180: *
181: * Results:
182: * True if the object looks like an array signature, false
183: * otherwise.
184: *
185: * Side effects:
186: * None.
187: *
188: *----------------------------------------------------------------------
189: */
190:
191: static boolean looksLikeArraySig(Interp interp, // Current interpreter.
192: TclObject signature) // TclObject to check.
193: throws TclException {
194: InternalRep rep = signature.getInternalRep();
195: int sigLen;
196: String clsName;
197:
198: if (rep instanceof FuncSig) {
199: // The string rep of FuncSig can never represent an ArraySig,
200: // so we know for sure that signature doesn't look like an
201: // ArraySig.
202:
203: return false;
204: }
205: if (rep instanceof ArraySig) {
206: return true;
207: }
208:
209: sigLen = TclList.getLength(interp, signature);
210: if (sigLen < 1) {
211: return false;
212: } else if (sigLen == 1) {
213: clsName = signature.toString();
214: } else {
215: clsName = TclList.index(interp, signature, 0).toString();
216: }
217:
218: if (clsName.endsWith("[]") || clsName.startsWith("[")) {
219: return true;
220: } else {
221: return false;
222: }
223: }
224:
225: /*
226: *----------------------------------------------------------------------
227: *
228: * get --
229: *
230: * Returns the ArraySig internal representation of the constructor
231: * or method that matches with the signature and the parameters.
232: *
233: * Results:
234: * The ArraySig given by the signature.
235: *
236: * Side effects:
237: * When successful, the internalRep of the signature object is
238: * converted to ArraySig.
239: *
240: *----------------------------------------------------------------------
241: */
242:
243: static ArraySig get(Interp interp, // Current interpreter. Stores error message
244: // if signature doesn't contain an array sig.
245: TclObject signature) // The TclObject to convert.
246: throws TclException // Standard Tcl exception.
247: {
248: InternalRep rep = signature.getInternalRep();
249: if ((rep instanceof ArraySig)) {
250: // The cached internal rep is a valid array signature, return it.
251:
252: return (ArraySig) rep;
253: }
254:
255: trying: {
256: if (TclList.getLength(interp, signature) != 1) {
257: break trying;
258: }
259:
260: String clsName = signature.toString();
261: if (!(clsName.endsWith("[]")) && !(clsName.startsWith("["))) {
262: break trying;
263: }
264: Class arrayType = JavaInvoke
265: .getClassByName(interp, clsName);
266:
267: Class componentType = arrayType;
268: while (componentType.isArray()) {
269: componentType = componentType.getComponentType();
270: }
271:
272: if (!PkgInvoker.isAccessible(componentType)) {
273: JavaInvoke.notAccessibleError(interp, componentType);
274: }
275:
276: int dimensions = 0;
277:
278: if (clsName.charAt(0) == '[') {
279: // If the string begins with '[', count the leading '['s.
280:
281: while (clsName.charAt(++dimensions) == '[') {
282: }
283:
284: } else {
285: // If the string is of the form className[][]..., count
286: // the trailing "[]"s.
287:
288: int end = clsName.length() - 1;
289: while ((end > 0) && (clsName.charAt(end - 1) == '[')
290: && (clsName.charAt(end) == ']')) {
291: dimensions++;
292: end -= 2;
293: ;
294: }
295: }
296:
297: ArraySig sigRep = new ArraySig(arrayType, dimensions);
298:
299: signature.setInternalRep(sigRep);
300: return sigRep;
301: }
302:
303: throw new TclException(interp, "bad array signature \""
304: + signature + "\"");
305: }
306:
307: } // end ArraySig
|