001: // Copyright (c) 1999 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: MethodProc[] methods;
013: int count;
014: int minArgs;
015: int maxArgs;
016:
017: public int numArgs() {
018: return minArgs | (maxArgs << 12);
019: }
020:
021: public void add(MethodProc method) {
022: if (methods == null)
023: methods = new MethodProc[8];
024: else if (count >= methods.length) {
025: MethodProc[] copy = new MethodProc[2 * methods.length];
026: System.arraycopy(methods, 0, copy, 0, count);
027: methods = copy;
028: }
029: methods[count++] = method;
030:
031: int n = method.minArgs();
032: if (n < minArgs)
033: minArgs = n;
034: n = method.maxArgs();
035: if (n == -1 || n > maxArgs)
036: maxArgs = n;
037: }
038:
039: public Object applyN(Object[] args) throws Throwable {
040: checkArgCount(this , args.length);
041: MethodProc best = null;
042: CallContext bestVars = null;
043: CallContext vars = null;
044: for (int i = count; --i >= 0;) {
045: MethodProc method = methods[i];
046: if (vars == null)
047: vars = new CallContext();
048: if (method.match(vars, args) == 0) {
049: if (best == null) {
050: best = method;
051: bestVars = vars;
052: vars = null;
053: } else {
054: best = MethodProc.mostSpecific(best, method);
055: if (best == method) {
056: bestVars = vars;
057: vars = null;
058: }
059: }
060:
061: }
062: }
063: if (best == null)
064: throw new WrongType(this , WrongType.ARG_UNKNOWN, null);
065: return best.applyV(bestVars);
066: }
067:
068: public int isApplicable(Type[] args) {
069: int best = -1;
070: for (int i = count; --i >= 0;) {
071: MethodProc method = methods[i];
072: int result = method.isApplicable(args);
073: if (result == 1)
074: return 1;
075: if (result == 0)
076: best = 0;
077: }
078: return best;
079: }
080:
081: public int match(CallContext ctx, Object[] args) {
082: if (count == 1)
083: return methods[0].match(ctx, args);
084: MethodProc best = null;
085: CallContext vars = null;
086: CallContext bestVars = null;
087: for (int i = count; --i >= 0;) {
088: MethodProc method = methods[i];
089: if (vars == null)
090: vars = new CallContext();
091: int code = method.match(vars, args);
092: if (code == 0) {
093: if (best == null) {
094: best = method;
095: bestVars = vars;
096: vars = null;
097: } else {
098: best = MethodProc.mostSpecific(best, method);
099: if (best == method) {
100: bestVars = vars;
101: vars = null;
102: }
103: }
104:
105: }
106: }
107: if (best != null) {
108: ctx.value1 = best;
109: ctx.value2 = bestVars;
110: return 0;
111: }
112: return NO_MATCH;
113: }
114:
115: public Object applyV(CallContext ctx) throws Throwable {
116: return ((MethodProc) ctx.value1)
117: .applyV((CallContext) ctx.value2);
118: }
119:
120: /** Create a GenericProc from one or more methods, plus properties. */
121: public static GenericProc make(Object[] args) {
122: int alen = args.length;
123: int mlen = 0;
124: GenericProc result = new GenericProc();
125: for (int i = 0; i < alen; i++) {
126: Object arg = args[i];
127: if (arg instanceof Keyword) {
128: String name = ((Keyword) arg).getName();
129: Object value = args[++i];
130: if (name == "name")
131: result.setName(value.toString());
132: else if (name == "method")
133: result.add((MethodProc) value);
134: else
135: result.setProperty(name, value);
136: } else
137: result.add((MethodProc) arg);
138: }
139: return result;
140: }
141: }
|