001: // Copyright (c) Corporation for National Research Initiatives
002: package org.python.core;
003:
004: class ReflectedArgs {
005: public Class[] args;
006:
007: public Object data;
008:
009: public Class declaringClass;
010:
011: public boolean isStatic;
012:
013: public int flags;
014:
015: public static final int StandardCall = 0;
016:
017: public static final int PyArgsCall = 1;
018:
019: public static final int PyArgsKeywordsCall = 2;
020:
021: public ReflectedArgs(Object data, Class[] args,
022: Class declaringClass, boolean isStatic) {
023: this .data = data;
024: this .args = args;
025: this .declaringClass = declaringClass;
026: this .isStatic = isStatic;
027:
028: if (args.length == 1 && args[0] == PyObject[].class) {
029: this .flags = PyArgsCall;
030: } else if (args.length == 2 && args[0] == PyObject[].class
031: && args[1] == String[].class) {
032: this .flags = PyArgsKeywordsCall;
033: } else {
034: this .flags = StandardCall;
035: }
036: }
037:
038: public boolean matches(PyObject self, PyObject[] pyArgs,
039: String[] keywords, ReflectedCallData callData) {
040: if (this .flags != PyArgsKeywordsCall) {
041: if (keywords != null && keywords.length != 0) {
042: return false;
043: }
044: }
045:
046: // if (isStatic ? self != null : self == null) return Py.NoConversion;
047: /* Ugly code to handle mismatch in static vs. instance functions... */
048: /*
049: * Will be very inefficient in cases where static and instance functions
050: * both exist with same names and number of args
051: */
052: if (this .isStatic) {
053: if (self != null) {
054: /*
055: * PyObject[] newArgs = new PyObject[pyArgs.length+1];
056: * System.arraycopy(pyArgs, 0, newArgs, 1, pyArgs.length);
057: * newArgs[0] = self; pyArgs = newArgs;
058: */
059: self = null;
060: }
061: } else {
062: if (self == null) {
063: if (pyArgs.length == 0) {
064: return false;
065: }
066: self = pyArgs[0];
067: PyObject[] newArgs = new PyObject[pyArgs.length - 1];
068: System.arraycopy(pyArgs, 1, newArgs, 0, newArgs.length);
069: pyArgs = newArgs;
070: }
071: }
072:
073: if (this .flags == PyArgsKeywordsCall) { // foo(PyObject[], String[])
074: callData.setLength(2);
075: callData.args[0] = pyArgs;
076: callData.args[1] = keywords;
077: callData.self = self;
078: if (self != null) {
079: Object tmp = self.__tojava__(this .declaringClass);
080: if (tmp != Py.NoConversion) {
081: callData.self = tmp;
082: }
083: }
084: return true;
085: } else if (this .flags == PyArgsCall) { // foo(PyObject[])
086: callData.setLength(1);
087: callData.args[0] = pyArgs;
088: callData.self = self;
089: if (self != null) {
090: Object tmp = self.__tojava__(this .declaringClass);
091: if (tmp != Py.NoConversion) {
092: callData.self = tmp;
093: }
094: }
095: return true;
096: }
097:
098: int n = this .args.length;
099: if (pyArgs.length != n) {
100: return false;
101: }
102:
103: // Make error messages clearer
104: callData.errArg = -1;
105:
106: if (self != null) {
107: Object tmp = self.__tojava__(this .declaringClass);
108: if (tmp == Py.NoConversion) {
109: return false;
110: }
111: callData.self = tmp;
112: } else {
113: callData.self = null;
114: }
115:
116: callData.setLength(n);
117: Object[] javaArgs = callData.args;
118:
119: for (int i = 0; i < n; i++) {
120: if ((javaArgs[i] = pyArgs[i].__tojava__(this .args[i])) == Py.NoConversion) {
121: // Make error messages clearer
122: if (i > callData.errArg) {
123: callData.errArg = i;
124: }
125: return false;
126: }
127: }
128: return true;
129: }
130:
131: public static int precedence(Class arg) {
132: if (arg == Object.class) {
133: return 3000;
134: }
135: if (arg.isPrimitive()) {
136: if (arg == Long.TYPE) {
137: return 10;
138: }
139: if (arg == Integer.TYPE) {
140: return 11;
141: }
142: if (arg == Short.TYPE) {
143: return 12;
144: }
145: if (arg == Character.TYPE) {
146: return 13;
147: }
148: if (arg == Byte.TYPE) {
149: return 14;
150: }
151: if (arg == Double.TYPE) {
152: return 20;
153: }
154: if (arg == Float.TYPE) {
155: return 21;
156: }
157: if (arg == Boolean.TYPE) {
158: return 30;
159: }
160: }
161: // Consider Strings a primitive type
162: // This makes them higher priority than byte[]
163: if (arg == String.class) {
164: return 40;
165: }
166:
167: if (arg.isArray()) {
168: Class componentType = arg.getComponentType();
169: if (componentType == Object.class) {
170: return 2500;
171: }
172: return 100 + precedence(componentType);
173: }
174: return 2000;
175: }
176:
177: /*
178: * Returns 0 iff arg1 == arg2 Returns +/-1 iff arg1 and arg2 are
179: * unimportantly different Returns +/-2 iff arg1 and arg2 are significantly
180: * different
181: */
182: public static int compare(Class arg1, Class arg2) {
183: int p1 = precedence(arg1);
184: int p2 = precedence(arg2);
185: // Special code if they are both nonprimitives
186: // Superclasses/superinterfaces are considered greater than sub's
187: if (p1 >= 2000 && p2 >= 2000) {
188: if (arg1.isAssignableFrom(arg2)) {
189: if (arg2.isAssignableFrom(arg1)) {
190: return 0;
191: } else {
192: return +2;
193: }
194: } else {
195: if (arg2.isAssignableFrom(arg1)) {
196: return -2;
197: } else {
198: int cmp = arg1.getName().compareTo(arg2.getName());
199: return cmp > 0 ? +1 : -1;
200: }
201: }
202: }
203: return p1 > p2 ? +2 : (p1 == p2 ? 0 : -2);
204: }
205:
206: public static final int REPLACE = 1998;
207:
208: public int compareTo(ReflectedArgs other) {
209: Class[] oargs = other.args;
210:
211: // First decision based on flags
212: if (other.flags != this .flags) {
213: return other.flags < this .flags ? -1 : +1;
214: }
215:
216: // Decision based on number of args
217: int n = this .args.length;
218: if (n < oargs.length) {
219: return -1;
220: }
221: if (n > oargs.length) {
222: return +1;
223: }
224:
225: // Decide based on static/non-static
226: if (this .isStatic && !other.isStatic) {
227: return +1;
228: }
229: if (!this .isStatic && other.isStatic) {
230: return -1;
231: }
232: // Compare the arg lists
233: int cmp = 0;
234: for (int i = 0; i < n; i++) {
235: int tmp = compare(this .args[i], oargs[i]);
236: if (tmp == +2 || tmp == -2) {
237: cmp = tmp;
238: }
239: if (cmp == 0) {
240: cmp = tmp;
241: }
242: }
243:
244: if (cmp != 0) {
245: return cmp > 0 ? +1 : -1;
246: }
247:
248: // If arg lists are equivalent, look at declaring classes
249: boolean replace = other.declaringClass
250: .isAssignableFrom(this .declaringClass);
251:
252: // For static methods, use the child's version
253: // For instance methods, use the parent's version
254: if (!this .isStatic) {
255: replace = !replace;
256: }
257:
258: return replace ? REPLACE : 0;
259: }
260:
261: public String toString() {
262: String s = "" + this .declaringClass + ", " + this .isStatic
263: + ", " + this .flags + ", " + this .data + "\n";
264: s = s + "\t(";
265: for (int j = 0; j < this .args.length; j++) {
266: s += this .args[j].getName() + ", ";
267: }
268: s += ")";
269: return s;
270: }
271: }
|