/* * JavaNewCmd.java -- * * Implements the built-in "java::new" command. * * Copyright (c) 1997 Sun Microsystems, Inc. All rights reserved. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. * * RCS: @(#) $Id: JavaNewCmd.java,v 1.1.1.1 1998/10/14 21:09:13 cvsadmin Exp $ * */ package tcl.lang; /* * This class implements the built-in "java::new" command. */ class JavaNewCmd implements Command { /* *---------------------------------------------------------------------- * * cmdProc -- * * This procedure is invoked to process the "java::new" Tcl * comamnd. See the user documentation for details on what * it does. * * Results: * None. * * Side effects: * A standard Tcl result is stored in the interpreter. * *---------------------------------------------------------------------- */ public void cmdProc( Interp interp, // Current interpreter. TclObject argv[]) // Argument list. throws TclException // A standard Tcl exception. { if (argv.length < 2) { throw new TclNumArgsException(interp, 1, argv, "signature ?arg arg ...?"); } /* * The "java::new" command can take both array signatures and * constructor signatures. We want to know what type of signature * is given without throwing and catching exceptions. Thus, we * call ArraySig.looksLikeArraySig() to determine quickly whether * a argv[1] can be interpreted as an array signature or a * constructor signature. This is a much less expensive way than * calling ArraySig.get() and then calling JavaInvoke.newInstance() * if that fails. */ if (ArraySig.looksLikeArraySig(interp, argv[1])) { /* * Create a new Java array object. */ if ((argv.length < 3) || (argv.length > 4)) { throw new TclNumArgsException(interp, 2, argv, "sizeList ?valueList?"); } ArraySig sig = ArraySig.get(interp, argv[1]); Class componentType = sig.componentType; int dimensions = sig.dimensions; TclObject sizeListObj = argv[2]; int sizeListLen = TclList.getLength(interp, sizeListObj); if (sizeListLen > dimensions) { throw new TclException(interp, "size list \"" + sizeListObj + "\" doesn't match array dimension (" + dimensions + ")"); } TclObject valueListObj = null; if (argv.length == 4) { valueListObj = argv[3]; } /* * Initialize arrayObj according to dimensions of both * sizeListObj and valueListObj. */ Object obj = ArrayObject.initArray(interp, sizeListObj, sizeListLen, 0, dimensions, componentType, valueListObj); interp.setResult(ReflectObject.newInstance(interp,componentType,obj)); } else { /* * Create a new (scalar) Java object. */ int startIdx = 2; int count = argv.length - startIdx; interp.setResult(JavaInvoke.newInstance(interp, argv[1], argv, startIdx, count)); } } } // end JavaNewCmd /* * The ArraySig class is used internally by the JavaNewCmd * class. ArraySig implements a new Tcl object type that represents an * array signature used for creating Java arrays. Examples or array * signatures are "int[][]", "java.lang.Object[]" or "[[D". */ class ArraySig extends InternalRep { /* * The base component type of the array. For example, the component * type for int[][][] is int. */ Class componentType; /* * The number of dimensions specified by the signature. For example, * int[][][] has a dimension of 3. */ int dimensions; /* *---------------------------------------------------------------------- * * ArraySig -- * * Creates a new ArraySig instance. * * Side effects: * Member fields are initialized. * *---------------------------------------------------------------------- */ ArraySig( Class cType, // Initial value for componentType. int n) // Initial value for dimensions. { componentType = cType; dimensions = n; } /* *---------------------------------------------------------------------- * * duplicate -- * * Make a copy of an object's internal representation. * * Results: * Returns a newly allocated instance of the appropriate type. * * Side effects: * None. * *---------------------------------------------------------------------- */ protected InternalRep duplicate() { return new ArraySig(componentType, dimensions); } /* *---------------------------------------------------------------------- * * looksLikeArraySig -- * * This method quickly determines whether a TclObject can be * interpreted as an array signature or a constructor signature. * * Results: * True if the object looks like an array signature, false * otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ static boolean looksLikeArraySig( Interp interp, // Current interpreter. TclObject signature) // TclObject to check. throws TclException { InternalRep rep = signature.getInternalRep(); if (rep instanceof FuncSig) { /* * The string rep of FuncSig can never represent an ArraySig, * so we know for sure that signature doesn't look like an * ArraySig. */ return false; } if (rep instanceof ArraySig) { return true; } if (TclList.getLength(interp, signature) < 1) { return false; } String clsName = TclList.index(interp, signature, 0).toString(); if (clsName.endsWith("[]") || clsName.startsWith("[")) { return true; } else { return false; } } /* *---------------------------------------------------------------------- * * get -- * * Returns the ArraySig internal representation of the constructor * or method that matches with the signature and the parameters. * * Results: * The ArraySig given by the signature. * * Side effects: * When successful, the internalRep of the signature object is * converted to ArraySig. * *---------------------------------------------------------------------- */ static ArraySig get( Interp interp, // Current interpreter. Stores error message // if signature doesn't contain an array sig. TclObject signature) // The TclObject to convert. throws TclException // Standard Tcl exception. { InternalRep rep = signature.getInternalRep(); if ((rep instanceof ArraySig)) { /* * The cached internal rep is a valid array signature, return it. */ return (ArraySig)rep; } trying: { if (TclList.getLength(interp, signature) != 1) { break trying; } String clsName = TclList.index(interp, signature, 0).toString(); if (!(clsName.endsWith("[]")) && !(clsName.startsWith("["))) { break trying; } Class componentType = JavaInvoke.getClassByName(interp, clsName); int dimensions = 0; if (clsName.charAt(0) == '[') { /* * If the string begins with '[', count the leading '['s. */ String tmp = clsName; while (tmp.charAt(++dimensions) == '[') { } } else { /* * If the string is of the form className[][]..., count * the trailing "[]"s. */ String tmp = clsName; for (; tmp.endsWith("[]"); dimensions++) { tmp = tmp.substring(0, tmp.length() - 2); } } ArraySig sigRep = new ArraySig(componentType, dimensions); signature.setInternalRep(sigRep); return sigRep; } throw new TclException(interp, "bad array signature \"" + signature + "\""); } } // end ArraySig