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