1 package gnu.kawa.functions;
2 
3 import gnu.expr.Language;
4 import gnu.lists.Strings;
5 import gnu.mapping.*;
6 import gnu.kawa.reflect.Invoke;
7 /* #ifdef use:java.lang.invoke */
8 import java.lang.invoke.*;
9 /* #else */
10 // import gnu.mapping.CallContext.MethodHandle;
11 /* #endif */
12 import gnu.lists.*;
13 import java.util.List;
14 import gnu.text.Char;
15 
16 /** Implement the standard Scheme function "apply".
17  * This has been generalized so that the last (list argument)
18  * can be any sequence, or any primitive array coercible to Object[]. */
19 
20 public class ApplyToArgs extends ProcedureN
21 {
ApplyToArgs(String name, Language language)22   public ApplyToArgs (String name, Language language)
23   {
24     super(name);
25     applyToObjectMethod = applyToObjectA2A;
26     applyToConsumerMethod = applyToConsumerA2A;
27     this.language = language;
28     setProperty(Procedure.validateXApplyKey,
29                 "gnu.kawa.functions.CompilationHelpers:validateApplyToArgs");
30   }
31 
32   Language language;
33 
index(CharSequence str, Object index)34     public static Object index(CharSequence str, Object index) {
35         IntSequence indexes = Sequences.asIntSequenceOrNull(index);
36         if (indexes != null) {
37             return Strings.indirectIndexed(str, indexes);
38         } else {
39             int iindex = ((Number) index).intValue();
40             return Char.valueOf(Strings.indexByCodePoints(str, iindex));
41         }
42     }
43 
apply1(Object arg1,Object arg2)44     public Object apply1(Object arg1,Object arg2) throws Throwable {
45         if (arg1 instanceof Procedure)
46             return ((Procedure) arg1).apply0();
47         return super.apply1(arg1);
48     }
49 
apply2(Object arg1, Object arg2)50     public Object apply2(Object arg1, Object arg2) throws Throwable {
51         if (arg1 instanceof Procedure)
52             return ((Procedure) arg1).apply1(arg2);
53         return super.apply2(arg1, arg2);
54     }
55 
apply3(Object arg1, Object arg2, Object arg3)56     public Object apply3(Object arg1, Object arg2, Object arg3)
57             throws Throwable {
58         if (arg1 instanceof Procedure)
59             return ((Procedure) arg1).apply2(arg2, arg3);
60         return super.apply3(arg1, arg2, arg3);
61     }
62 
apply4(Object arg1, Object arg2, Object arg3, Object arg4)63     public Object apply4(Object arg1, Object arg2, Object arg3, Object arg4)
64             throws Throwable {
65         if (arg1 instanceof Procedure)
66             return ((Procedure) arg1).apply3(arg2, arg3, arg4);
67         return super.apply4(arg1, arg2, arg3, arg4);
68     }
69 
applyN(Object[] args)70     public Object applyN (Object[] args) throws Throwable {
71         Object proc = Promise.force(args[0]);
72         if (proc instanceof Procedure) {
73             Object[] rargs = new Object[args.length-1];
74             System.arraycopy(args, 1, rargs, 0, rargs.length);
75             return ((Procedure) proc).applyN(rargs);
76         }
77         if (proc instanceof gnu.bytecode.Type
78             || proc instanceof Class) {
79             return gnu.kawa.reflect.Invoke.make.applyN(args);
80         }
81         if (proc instanceof CharSequence) {
82             if (args.length != 2)
83                 throw new WrongArguments(this, args.length); // FIXME
84             return index((CharSequence) proc, Promise.force(args[1]));
85         }
86         if (proc instanceof gnu.lists.Array) {
87             return ComposedArray.generalIndex((Array) proc, false,
88                                               1, args.length-1, args);
89         }
90         if (proc instanceof gnu.lists.Array) {
91             return ComposedArray.generalIndex((Array) proc, false,
92                                               1, args.length-1, args);
93         }
94         if (proc instanceof List) {
95             if (args.length != 2)
96                 throw new WrongArguments(this, args.length); // FIXME
97             List lst = (List) proc;
98             Object arg1 = Promise.force(args[1]);
99             IntSequence indexes = Sequences.asIntSequenceOrNull(arg1);
100             if (indexes != null) {
101                 return Sequences.indirectIndexed(lst, indexes);
102             } else {
103                 int index = ((Number) arg1).intValue();
104                 return lst.get(index);
105 
106             }
107         }
108         /*
109           What should happen if key has no associated value?
110           Throw an exception?  Return null?
111         if (proc instanceof java.util.Map) {
112             if (args.length != 2)
113                 throw new WrongArguments(this, args.length); // FIXME
114             Object key = Promise.force(args[1]);
115 
116         }
117         */
118         Class pclass = proc.getClass();
119         if (pclass.isArray()) {
120             if (args.length != 2)
121                 throw new WrongArguments(this, args.length); // FIXME
122             return java.lang.reflect.Array.get(proc, ((Number) args[1]).intValue());
123         }
124         throw new WrongType(this, 0, proc, "procedure");
125     }
126 
applyToConsumerA2A(Procedure proc, CallContext ctx)127     public static Object applyToConsumerA2A(Procedure proc, CallContext ctx) throws Throwable {
128         Object arg0 = Promise.force(ctx.getNextArg());
129         if (arg0 instanceof Procedure) {
130             proc = (Procedure) arg0;
131             ctx.shiftArgs(null, 1);
132             return proc.getApplyToConsumerMethod().invokeExact(proc, ctx);
133         }
134         Object r = applyRest(arg0, ctx);
135         if (r != ctx) {
136             ctx.consumer.writeObject(r);
137             r = null;
138         }
139         return r;
140     }
applyToObjectA2A(Procedure proc, CallContext ctx)141     public static Object applyToObjectA2A(Procedure proc, CallContext ctx) throws Throwable {
142         Object arg0 = Promise.force(ctx.getNextArg());
143         if (arg0 instanceof Procedure) {
144             proc = (Procedure) arg0;
145             ctx.shiftArgs(null, 1);
146             return proc.getApplyToObjectMethod().invokeExact(proc, ctx);
147         }
148         return applyRest(arg0, ctx);
149     }
150 
applyRest(Object arg0, CallContext ctx)151     private static Object applyRest(Object arg0, CallContext ctx) throws Throwable {
152         if (arg0 instanceof gnu.bytecode.Type
153             || arg0 instanceof Class) {
154             Procedure proc = gnu.kawa.reflect.Invoke.make;
155             ctx.rewind();
156             ctx.setNextProcedure(proc, null);
157             return proc.getApplyToObjectMethod().invokeExact(proc, ctx);
158         }
159         if (arg0 instanceof CharSequence) {
160             Object arg1 = Promise.force(ctx.getNextArg());
161             if (ctx.checkDone() != 0)
162                 return ctx;
163             IntSequence indexes = Sequences.asIntSequenceOrNull(arg1);
164             CharSequence str = (CharSequence) arg0;
165             if (indexes != null)
166                 return Strings.indirectIndexed(str, indexes);
167             if (! (arg1 instanceof Number))
168                 ctx.matchError(MethodProc.NO_MATCH_BAD_TYPE|2);
169             int iindex = ((Number) arg1).intValue();
170             return Char.valueOf(Strings.indexByCodePoints(str, iindex));
171         }
172         if (arg0 instanceof java.util.List) {
173             Object arg1 = Promise.force(ctx.getNextArg());
174             if (! (arg1 instanceof Number))
175                 ctx.matchError(MethodProc.NO_MATCH_BAD_TYPE|2);
176             if (ctx.checkDone() != 0)
177                 return ctx;
178             int index = ((Number) Promise.force(arg1)).intValue();
179             return ((java.util.List) arg0).get(index);
180         }
181         if (arg0 != null) {
182             Class pclass = arg0.getClass();
183             if (pclass.isArray()) {
184                 Object arg1 = ctx.getNextArg();
185                 if (! (arg1 instanceof Number))
186                     ctx.matchError(MethodProc.NO_MATCH_BAD_TYPE|2);
187                 if (ctx.checkDone() != 0)
188                     return ctx;
189                 int index = ((Number) Promise.force(arg1)).intValue();
190                 return java.lang.reflect.Array.get(arg0, index);
191             }
192             if (arg0 instanceof gnu.lists.Array) {
193                 Procedure proc = ArrayRef.arrayRef;
194                 ctx.next = 0;    // OR: ctx.shiftArgs(proc, 0);
195                 return proc.getApplyToObjectMethod().invokeExact(proc, ctx);
196             }
197             /*
198               What should happen if key has no associated value?
199               Throw an exception?  Return null?
200               if (arg0 instanceof java.util.Map) {
201               if (args.length != 2)
202               throw new WrongArguments(this, args.length); // FIXME
203               Object key = Promise.force(args[1]);
204 
205               }
206             */
207         }
208         if (ctx.throwOnException())
209             throw new WrongType(ctx.proc, 1, arg0, "procedure, sequence, or other operator");
210         else
211             ctx.matchError(MethodProc.NO_MATCH_BAD_TYPE|1);
212         return ctx;
213     }
214 
215     public static final MethodHandle applyToObjectA2A =
216         Procedure.lookupApplyHandle(ApplyToArgs.class, "applyToObjectA2A");
217     public static final MethodHandle applyToConsumerA2A =
218         Procedure.lookupApplyHandle(ApplyToArgs.class, "applyToConsumerA2A");
219 }
220