001: package gnu.kawa.functions;
002:
003: import gnu.bytecode.*;
004: import gnu.expr.*;
005: import gnu.mapping.*;
006: import gnu.kawa.reflect.Invoke;
007: import gnu.kawa.reflect.ArrayGet;
008:
009: /** Implement the standard Scheme function "apply".
010: * This has been generalized so that the last (list argument)
011: * can be any sequence, or any primitive array coercible to Object[]. */
012:
013: public class ApplyToArgs extends ProcedureN implements CanInline {
014: public int match1(Object arg1, CallContext ctx) {
015: if (arg1 instanceof Procedure)
016: return ((Procedure) arg1).match0(ctx);
017: else
018: return super .match1(arg1, ctx);
019: }
020:
021: public int match2(Object arg1, Object arg2, CallContext ctx) {
022: if (arg1 instanceof Procedure)
023: return ((Procedure) arg1).match1(arg2, ctx);
024: else
025: return super .match2(arg1, arg2, ctx);
026: }
027:
028: public int match3(Object arg1, Object arg2, Object arg3,
029: CallContext ctx) {
030: if (arg1 instanceof Procedure)
031: return ((Procedure) arg1).match2(arg2, arg3, ctx);
032: else
033: return super .match3(arg1, arg2, arg3, ctx);
034: }
035:
036: public int match4(Object arg1, Object arg2, Object arg3,
037: Object arg4, CallContext ctx) {
038: if (arg1 instanceof Procedure)
039: return ((Procedure) arg1).match3(arg2, arg3, arg4, ctx);
040: else
041: return super .match4(arg1, arg2, arg3, arg4, ctx);
042: }
043:
044: public int matchN(Object[] args, CallContext ctx) {
045: int n = args.length;
046: if (n > 0 && args[0] instanceof Procedure) {
047: Procedure proc = (Procedure) args[0];
048: switch (n) {
049: case 1:
050: return proc.match0(ctx);
051: case 2:
052: return proc.match1(args[1], ctx);
053: case 3:
054: return proc.match2(args[1], args[2], ctx);
055: case 4:
056: return proc.match3(args[1], args[2], args[3], ctx);
057: case 5:
058: return proc.match4(args[1], args[2], args[3], args[4],
059: ctx);
060: default:
061: Object[] xargs = new Object[n - 1];
062: System.arraycopy(args, 1, xargs, 0, n - 1);
063: return proc.matchN(xargs, ctx);
064: }
065: }
066: return super .matchN(args, ctx);
067: }
068:
069: public void check1(Object arg1, CallContext ctx) {
070: if (arg1 instanceof Procedure)
071: ((Procedure) arg1).check0(ctx);
072: else
073: super .check1(arg1, ctx);
074: }
075:
076: public void check2(Object arg1, Object arg2, CallContext ctx) {
077: if (arg1 instanceof Procedure)
078: ((Procedure) arg1).check1(arg2, ctx);
079: else
080: super .check2(arg1, arg2, ctx);
081: }
082:
083: public void check3(Object arg1, Object arg2, Object arg3,
084: CallContext ctx) {
085: if (arg1 instanceof Procedure)
086: ((Procedure) arg1).check2(arg2, arg3, ctx);
087: else
088: super .check3(arg1, arg2, arg3, ctx);
089: }
090:
091: public void check4(Object arg1, Object arg2, Object arg3,
092: Object arg4, CallContext ctx) {
093: if (arg1 instanceof Procedure)
094: ((Procedure) arg1).check3(arg2, arg3, arg4, ctx);
095: else
096: super .check4(arg1, arg2, arg3, arg4, ctx);
097: }
098:
099: public void checkN(Object[] args, CallContext ctx) {
100: int code = matchN(args, ctx);
101: if (code != 0) {
102: Procedure proc = this ;
103: if (args.length > 0 && args[0] instanceof Procedure) {
104: proc = (Procedure) args[0];
105: Object[] xargs = new Object[args.length - 1];
106: System.arraycopy(args, 1, xargs, 0, xargs.length);
107: args = xargs;
108: }
109: throw MethodProc.matchFailAsException(code, proc, args);
110: }
111: }
112:
113: public ApplyToArgs(String name, Language language) {
114: super (name);
115: this .language = language;
116: }
117:
118: Language language;
119:
120: public Expression inline(ApplyExp exp, ExpWalker walker) {
121: Expression[] args = exp.getArgs();
122: int nargs = args.length - 1;
123: if (nargs >= 0) {
124: Expression proc = args[0];
125: args[0] = proc;
126: Type ptype = proc.getType();
127: ApplyExp result;
128: Compilation comp = walker.getCompilation();
129: Language language = comp.getLanguage();
130: // This might be more cleanly handled at the type specifier. FIXME
131: if (Invoke.checkKnownClass(ptype, comp) < 0)
132: return exp;
133: ClassType ctype;
134: if (ptype.isSubtype(Compilation.typeProcedure)) {
135: Expression[] rargs = new Expression[nargs];
136: System.arraycopy(args, 1, rargs, 0, nargs);
137: result = new ApplyExp(proc, rargs);
138: } else if (ptype.isSubtype(Compilation.typeType)
139: || language.getTypeFor(proc, false) != null) {
140: result = new ApplyExp(Invoke.make, args);
141: } else if (ptype instanceof ArrayType) {
142: Type elementType = ((ArrayType) ptype)
143: .getComponentType();
144: result = new ApplyExp(new ArrayGet(elementType), args);
145: } else if (ptype instanceof ClassType
146: && (ctype = (ClassType) ptype).isSubclass(typeList)
147: && nargs == 1) {
148: // We search for a "get(int)" method, rather than just using
149: // typeList.getDeclaredMethod("get", 1) to see if we make a
150: // a virtual call rather than an interface call.
151: Method get = ctype.getMethod("get",
152: new Type[] { Type.int_type });
153: result = new ApplyExp(get, args);
154: } else
155: return exp;
156: result.setLine(exp);
157: return ((InlineCalls) walker).walkApplyOnly(result);
158: }
159: return exp;
160: }
161:
162: static final ClassType typeList
163: /* #ifdef JAVA2 */
164: = ClassType.make("java.util.List");
165:
166: /* #else */
167: // = ClassType.make("gnu.lists.Sequence");
168: /* #endif */
169:
170: public Object applyN(Object[] args) throws Throwable {
171: Object proc = args[0];
172: Object[] rargs = new Object[args.length - 1];
173: System.arraycopy(args, 1, rargs, 0, rargs.length);
174: if (proc instanceof Procedure) {
175: return ((Procedure) proc).applyN(rargs);
176: }
177: if (proc instanceof gnu.bytecode.Type) {
178: return gnu.kawa.reflect.Invoke.make.applyN(args);
179: }
180: if (proc instanceof
181: /* #ifdef JAVA2 */
182: java.util.List
183: /* #else */
184: // gnu.lists.Sequence
185: /* #endif */
186: ) {
187: if (args.length != 2)
188: throw new WrongArguments(this , args.length); // FIXME
189: int index = ((Number) rargs[0]).intValue();
190: /* #ifdef JAVA2 */
191: return ((java.util.List) proc).get(index);
192: /* #else */
193: // return ((gnu.lists.Sequence) proc).get(index);
194: /* #endif */
195: }
196: Class pclass = proc.getClass();
197: if (pclass.isArray()) {
198: if (args.length != 2)
199: throw new WrongArguments(this , args.length); // FIXME
200: return java.lang.reflect.Array.get(proc,
201: ((Number) rargs[0]).intValue());
202: }
203: throw new WrongType(this , 0, proc, "procedure");
204: }
205: }
|