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: /**
037: The name of this class is somewhat misleading. This covers both the case
038: where there is an array initializer and
039: */
040: class BSHArrayDimensions extends SimpleNode {
041: public Class baseType;
042: public int numDefinedDims;
043: public int numUndefinedDims;
044: /**
045: The Length in each defined dimension. This value set by the eval()
046: Since the values can come from Expressions we should be re-eval()d each
047: time.
048: */
049: public int[] definedDimensions;
050:
051: BSHArrayDimensions(int id) {
052: super (id);
053: }
054:
055: public void addDefinedDimension() {
056: numDefinedDims++;
057: }
058:
059: public void addUndefinedDimension() {
060: numUndefinedDims++;
061: }
062:
063: public Object eval(Class type, CallStack callstack,
064: Interpreter interpreter) throws EvalError {
065: if (Interpreter.DEBUG)
066: Interpreter.debug("array base type = " + type);
067: baseType = type;
068: return eval(callstack, interpreter);
069: }
070:
071: /**
072: Evaluate the structure of the array in one of two ways:
073:
074: a) an initializer exists, evaluate it and return
075: the fully constructed array object, also record the dimensions
076: of that array
077:
078: b) evaluate and record the lengths in each dimension and
079: return void.
080:
081: The structure of the array dims is maintained in dimensions.
082: */
083: public Object eval(CallStack callstack, Interpreter interpreter)
084: throws EvalError {
085: SimpleNode child = (SimpleNode) jjtGetChild(0);
086:
087: /*
088: Child is array initializer. Evaluate it and fill in the
089: dimensions it returns. Initialized arrays are always fully defined
090: (no undefined dimensions to worry about).
091: The syntax uses the undefinedDimension count.
092: e.g. int [][] { 1, 2 };
093: */
094: if (child instanceof BSHArrayInitializer) {
095: if (baseType == null)
096: throw new EvalError(
097: "Internal Array Eval err: unknown base type",
098: this , callstack);
099:
100: Object initValue = ((BSHArrayInitializer) child).eval(
101: baseType, numUndefinedDims, callstack, interpreter);
102:
103: Class arrayClass = initValue.getClass();
104: int actualDimensions = Reflect
105: .getArrayDimensions(arrayClass);
106: definedDimensions = new int[actualDimensions];
107:
108: // Compare with number of dimensions actually created with the
109: // number specified (syntax uses the undefined ones here)
110: if (definedDimensions.length != numUndefinedDims)
111: throw new EvalError(
112: "Incompatible initializer. Allocation calls for a "
113: + numUndefinedDims
114: + " dimensional array, but initializer is a "
115: + actualDimensions
116: + " dimensional array", this , callstack);
117:
118: // fill in definedDimensions [] lengths
119: Object arraySlice = initValue;
120: for (int i = 0; i < definedDimensions.length; i++) {
121: definedDimensions[i] = Array.getLength(arraySlice);
122: if (definedDimensions[i] > 0)
123: arraySlice = Array.get(arraySlice, 0);
124: }
125:
126: return initValue;
127: } else
128: // Evaluate the defined dimensions of the array
129: {
130: definedDimensions = new int[numDefinedDims];
131:
132: for (int i = 0; i < numDefinedDims; i++) {
133: try {
134: Object length = ((SimpleNode) jjtGetChild(i)).eval(
135: callstack, interpreter);
136: definedDimensions[i] = ((Primitive) length)
137: .intValue();
138: } catch (Exception e) {
139: throw new EvalError("Array index: " + i
140: + " does not evaluate to an integer", this,
141: callstack);
142: }
143: }
144: }
145:
146: return Primitive.VOID;
147: }
148: }
|