001: // Copyright (c) 1999, 2004 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.expr;
005:
006: import gnu.mapping.*;
007: import gnu.bytecode.Type;
008:
009: /** A collection of MethodProcs; one is chosen at apply time. */
010:
011: public class GenericProc extends MethodProc {
012: protected MethodProc[] methods;
013: int count;
014: int minArgs;
015: int maxArgs;
016:
017: public GenericProc(String name) {
018: setName(name);
019: }
020:
021: public GenericProc() {
022: }
023:
024: public int numArgs() {
025: return minArgs | (maxArgs << 12);
026: }
027:
028: protected synchronized void add(MethodProc[] procs) {
029: int n = procs.length;
030: if (methods == null)
031: methods = new MethodProc[n];
032: for (int i = 0; i < n; i++)
033: add(procs[i]);
034: }
035:
036: public synchronized void add(MethodProc method) {
037: if (methods == null)
038: methods = new MethodProc[8];
039: else if (count >= methods.length) {
040: MethodProc[] copy = new MethodProc[2 * methods.length];
041: System.arraycopy(methods, 0, copy, 0, count);
042: methods = copy;
043: }
044:
045: int i;
046: for (i = 0; i < count; i++) {
047: MethodProc best = MethodProc.mostSpecific(method,
048: methods[i]);
049: if (best == method)
050: break;
051: }
052: if (i < count)
053: System.arraycopy(methods, i, methods, i + 1, count - i);
054: methods[i] = method;
055:
056: int n = method.minArgs();
057: if (n < minArgs || count == 0)
058: minArgs = n;
059: n = method.maxArgs();
060: if (n == -1 || n > maxArgs)
061: maxArgs = n;
062: count++;
063: }
064:
065: /* Possibly optimization. Likewise for apply0, apply2, apply3, apply4.
066: public Object apply1 (Object arg1) throws Throwable
067: {
068: if (numArgs() != 0x1001)
069: {
070: Object[] args = { arg1 };
071: return applyN(args);
072: }
073: CallContext ctx = CallContext.getInstance();
074: for (int i = 0; i < count; i++)
075: {
076: MethodProc method = methods[i];
077: if (method.match1(arg1, ctx) == 0)
078: return method.applyV(ctx);
079: }
080: throw new WrongType(this, WrongType.ARG_UNKNOWN, null);
081: }
082: */
083:
084: public Object applyN(Object[] args) throws Throwable {
085: if (count == 1)
086: return methods[0].applyN(args);
087: checkArgCount(this , args.length);
088: CallContext ctx = CallContext.getInstance();
089: for (int i = 0; i < count; i++) {
090: MethodProc method = methods[i];
091: int m = method.matchN(args, ctx);
092: if (m == 0)
093: return ctx.runUntilValue();
094: }
095: throw new WrongType(this , WrongType.ARG_UNKNOWN, null);
096: }
097:
098: public int isApplicable(Type[] args) {
099: int best = -1;
100: for (int i = count; --i >= 0;) {
101: MethodProc method = methods[i];
102: int result = method.isApplicable(args);
103: if (result == 1)
104: return 1;
105: if (result == 0)
106: best = 0;
107: }
108: return best;
109: }
110:
111: public int match0(CallContext ctx) {
112: if (count == 1)
113: return methods[0].match0(ctx);
114: for (int i = 0; i < count; i++) {
115: MethodProc method = methods[i];
116: int code = method.match0(ctx);
117: if (code == 0)
118: return 0;
119: }
120: ctx.proc = null;
121: return NO_MATCH;
122: }
123:
124: public int match1(Object arg1, CallContext ctx) {
125: if (count == 1)
126: return methods[0].match1(arg1, ctx);
127: for (int i = 0; i < count; i++) {
128: MethodProc method = methods[i];
129: int code = method.match1(arg1, ctx);
130: if (code == 0)
131: return 0;
132: }
133: ctx.proc = null;
134: return NO_MATCH;
135: }
136:
137: public int match2(Object arg1, Object arg2, CallContext ctx) {
138: if (count == 1)
139: return methods[0].match2(arg1, arg2, ctx);
140: for (int i = 0; i < count; i++) {
141: MethodProc method = methods[i];
142: int code = method.match2(arg1, arg2, ctx);
143: if (code == 0)
144: return 0;
145: }
146: ctx.proc = null;
147: return NO_MATCH;
148: }
149:
150: public int match3(Object arg1, Object arg2, Object arg3,
151: CallContext ctx) {
152: if (count == 1)
153: return methods[0].match3(arg1, arg2, arg3, ctx);
154: for (int i = 0; i < count; i++) {
155: MethodProc method = methods[i];
156: int code = method.match3(arg1, arg2, arg3, ctx);
157: if (code == 0)
158: return 0;
159: }
160: ctx.proc = null;
161: return NO_MATCH;
162: }
163:
164: public int match4(Object arg1, Object arg2, Object arg3,
165: Object arg4, CallContext ctx) {
166: if (count == 1)
167: return methods[0].match4(arg1, arg2, arg3, arg4, ctx);
168: for (int i = 0; i < count; i++) {
169: MethodProc method = methods[i];
170: int code = method.match4(arg1, arg2, arg3, arg4, ctx);
171: if (code == 0)
172: return 0;
173: }
174: ctx.proc = null;
175: return NO_MATCH;
176: }
177:
178: public int matchN(Object[] args, CallContext ctx) {
179: if (count == 1)
180: return methods[0].matchN(args, ctx);
181: int alen = args.length;
182: Type[] atypes = new Type[alen];
183: Language language = Language.getDefaultLanguage();
184: // As a rough approximation of finding the "best match", and also
185: // an approximation of what we do when selecting a method at compile-time,
186: // let's make a pre-pass to check which methods are applicable.
187: for (int j = 0; j < alen; j++) {
188: Object arg = args[j];
189: Type atype;
190: if (arg == null)
191: atype = Type.nullType;
192: else {
193: Class aclass = arg.getClass();
194: if (language != null)
195: atype = language.getTypeFor(aclass);
196: else
197: atype = Type.make(aclass);
198: }
199: atypes[j] = atype;
200: }
201: int[] codes = new int[count];
202: int defCount = 0;
203: int maybeCount = 0;
204: int bestIndex = -1;
205: for (int i = 0; i < count; i++) {
206: int code = methods[i].isApplicable(atypes);
207: if (defCount == 0 && code >= 0)
208: bestIndex = i;
209: if (code > 0)
210: defCount++;
211: else if (code == 0)
212: maybeCount++;
213: codes[i] = code;
214: }
215: if (defCount == 1 || (defCount == 0 && maybeCount == 1))
216: return methods[bestIndex].matchN(args, ctx);
217: for (int i = 0; i < count; i++) {
218: int code = codes[i];
219: if (code < 0 || (code == 0 && defCount > 0))
220: continue;
221: MethodProc method = methods[i];
222: code = method.matchN(args, ctx);
223: if (code == 0)
224: return 0;
225: }
226: ctx.proc = null;
227: return NO_MATCH;
228: }
229:
230: public final void setProperties(Object[] args) {
231: int alen = args.length;
232: for (int i = 0; i < alen; i++) {
233: Object arg = args[i];
234: if (arg instanceof Keyword) {
235: String name = ((Keyword) arg).getName();
236: Object value = args[++i];
237: if (name == "name")
238: setName(value.toString());
239: else if (name == "method")
240: add((MethodProc) value);
241: else
242: setProperty(name, value);
243: } else
244: add((MethodProc) arg);
245: }
246: }
247:
248: /** Create a GenericProc from one or more methods, plus properties. */
249: public static GenericProc make(Object[] args) {
250: GenericProc result = new GenericProc();
251: result.setProperties(args);
252: return result;
253: }
254: }
|