001: /*
002: * @(#)Java2Configuration.java 1.3 05/05/09
003: *
004: * Copyright (c) 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.lang;
010:
011: import java.lang.reflect.Array;
012: import java.lang.reflect.Field;
013: import java.lang.reflect.InvocationTargetException;
014: import java.lang.reflect.Method;
015: import java.security.AccessController;
016: import java.security.PrivilegedActionException;
017: import java.security.PrivilegedExceptionAction;
018: import java.util.Collection;
019: import java.util.Collections;
020: import java.util.Enumeration;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import pnuts.lang.Package;
025:
026: /**
027: * This class define the interface of runtime configuration, such as how to find
028: * method/field candidates, how to get the field value, how to get indexed
029: * elements, and so on. This class also provides the default implmentation for
030: * Java2 of this interface.
031: *
032: * @see pnuts.lang.Configuration
033: */
034: class Java2Configuration extends JavaBeansConfiguration {
035:
036: private final static boolean DEBUG = false;
037:
038: static final long serialVersionUID = -4966352283575106111L;
039:
040: Java2Configuration() {
041: }
042:
043: Java2Configuration(Class stopClass) {
044: super (stopClass);
045: }
046:
047: /**
048: * Gets a field value of the target object.
049: *
050: * @param context
051: * the context in which the field is read
052: * @param target
053: * the target object
054: * @param name
055: * the field name
056: * @return the field value
057: */
058: public Object getField(Context context, Object target, String name) {
059: if (target instanceof Context) {
060: return ((Context) target).get(name);
061: } else if (target instanceof Property) {
062: return ((Property) target).get(name, context);
063: } else if (target instanceof Map) {
064: return ((Map) target).get(name);
065: } else if (target instanceof Generator) {
066: return fieldGenerator((Generator) target, name, context);
067: } else {
068: return super .getField(context, target, name);
069: }
070: }
071:
072: /**
073: * Sets a field value of the specified object.
074: *
075: * @param context
076: * the context in which the field is written.
077: * @param target
078: * the target object
079: * @param name
080: * the field name
081: * @param value
082: * the field value
083: */
084: public void putField(final Context context, Object target,
085: String name, final Object value) {
086: if (target instanceof Context) {
087: ((Context) target).set(name, value);
088: } else if (target instanceof Property) {
089: ((Property) target).set(name, value, context);
090: } else if (target instanceof Map) {
091: ((Map) target).put(name, value);
092: } else if (target instanceof Generator) {
093: Generator g = (Generator) target;
094: final String fieldName = name;
095: g.apply(new PnutsFunction() {
096: protected Object exec(Object[] args, Context c) {
097: putField(context, args[0], fieldName, value);
098: return null;
099: }
100: }, context);
101: } else {
102: super .putField(context, target, name, value);
103: }
104: }
105:
106: /**
107: * Get the value of a static field.
108: *
109: * @param context
110: * the context in which the field is accessed
111: * @param clazz
112: * the class in which the static field is defined
113: * @param name
114: * the name of the static field
115: * @return the value
116: */
117: public Object getStaticField(Context context, Class clazz,
118: String name) {
119: try {
120: return getField(clazz, name).get(null);
121: } catch (PnutsException p) {
122: throw p;
123: } catch (NoSuchFieldException f) {
124: throw new PnutsException("field.notFound", new Object[] {
125: name, clazz }, context);
126: } catch (Throwable t) {
127: throw new PnutsException(t, context);
128: }
129: }
130:
131: /**
132: * Sets a value to the static field of the specified class.
133: *
134: * @param context
135: * the context in which the field is written.
136: * @param clazz
137: * the class in which the static field is defined
138: * @param name
139: * the field name
140: * @param value
141: * the field value
142: */
143: public void putStaticField(Context context, Class clazz,
144: String name, Object value) {
145: try {
146: Field field = getField(clazz, name);
147: Class type = field.getType();
148: if (type.isArray() && value != null
149: && Runtime.isArray(value)) {
150: if (!type.isInstance(value)) {
151: // value = Runtime.transform(Runtime.getBottomType(type), value);
152: value = Runtime.transform(type, value, context);
153: }
154: }
155: field.set(null, value);
156: } catch (PnutsException e0) {
157: throw e0;
158: } catch (NoSuchFieldException f) {
159: throw new PnutsException("field.notFound", new Object[] {
160: name, clazz }, context);
161: } catch (Throwable e) {
162: throw new PnutsException(e, context);
163: }
164: }
165:
166: protected Field getField(final Class cls, final String name)
167: throws NoSuchFieldException {
168: try {
169: return (Field) AccessController
170: .doPrivileged(new PrivilegedExceptionAction() {
171: public Object run() throws Exception {
172: return cls.getField(name);
173: }
174: });
175: } catch (PrivilegedActionException e) {
176: throw (NoSuchFieldException) e.getException();
177: }
178: }
179:
180: /**
181: * Calls a method
182: *
183: * @param context
184: * the contexct
185: * @param c
186: * the class of the method
187: * @param name
188: * the name of the method
189: * @param args
190: * arguments
191: * @param types
192: * type information of each arguments
193: * @param target
194: * the target object of the method call
195: * @return the result of the method call
196: */
197: public Object callMethod(Context context, Class c, String name,
198: Object args[], Class types[], Object target) {
199: try {
200: if (target instanceof AbstractData) {
201: return ((AbstractData) target).invoke(name, args,
202: context);
203: }
204: return super .callMethod(context, c, name, args, types,
205: target);
206: } catch (PnutsException e1) {
207: throw e1;
208: } catch (Throwable e2) {
209: throw new PnutsException(e2, context);
210: }
211: }
212:
213: static class ObjectArrayEnum implements Enumeration {
214: Object[] array;
215: int idx;
216: int len;
217:
218: ObjectArrayEnum(Object[] array) {
219: this .array = array;
220: this .idx = 0;
221: this .len = array.length;
222: }
223:
224: public boolean hasMoreElements() {
225: return idx < len;
226: }
227:
228: public Object nextElement() {
229: return array[idx++];
230: }
231: }
232:
233: static class ArrayEnum implements Enumeration {
234: Object array;
235:
236: int idx;
237:
238: int len;
239:
240: ArrayEnum(Object array) {
241: this .array = array;
242: this .idx = 0;
243: this .len = Array.getLength(array);
244: }
245:
246: public boolean hasMoreElements() {
247: return idx < len;
248: }
249:
250: public Object nextElement() {
251: return Array.get(array, idx++);
252: }
253: }
254:
255: static class ItrEnum implements Enumeration {
256: Iterator itr;
257:
258: ItrEnum(Iterator itr) {
259: this .itr = itr;
260: }
261:
262: public boolean hasMoreElements() {
263: return itr.hasNext();
264: }
265:
266: public Object nextElement() {
267: return itr.next();
268: }
269: }
270:
271: static class StringEnum implements Enumeration {
272: String str;
273:
274: int len;
275:
276: int pos = 0;
277:
278: StringEnum(String str) {
279: this .str = str;
280: this .len = str.length();
281: }
282:
283: public boolean hasMoreElements() {
284: return len > pos;
285: }
286:
287: public Object nextElement() {
288: return new Character(str.charAt(pos++));
289: }
290: }
291:
292: /**
293: * Convert an object to Enumeration. This method is used by foreach
294: * statements. Subclasses can override this method to customize the behavior
295: * of foreach statements.
296: */
297: public Enumeration toEnumeration(Object obj) {
298: if (obj instanceof Enumeration) {
299: return (Enumeration) obj;
300: } else if (obj instanceof Iterator) {
301: return new ItrEnum((Iterator) obj);
302: } else if (obj instanceof Object[]) {
303: return new ObjectArrayEnum((Object[]) obj);
304: } else if (obj instanceof Collection) {
305: return Collections.enumeration((Collection) obj);
306: } else if (obj instanceof Map) {
307: return new ItrEnum(((Map) obj).entrySet().iterator());
308: } else if (Runtime.isArray(obj)) {
309: return new ArrayEnum(obj);
310: } else if (obj instanceof String) {
311: return new StringEnum((String) obj);
312: } else {
313: return null;
314: }
315: }
316:
317: public Callable toCallable(Object obj) {
318: return null;
319: }
320:
321: public Object getElement(Context context, final Object target,
322: Object key) {
323: if (target instanceof Object[]) {
324: if (key instanceof Number) {
325: return ((Object[]) target)[((Number) key).intValue()];
326: } else if (key instanceof PnutsFunction) {
327: return filterGenerator((Object[]) target,
328: (PnutsFunction) key, context);
329: }
330: } else if (target instanceof Indexed) {
331: if (key instanceof Number) {
332: return ((Indexed) target)
333: .get(((Number) key).intValue());
334: } else if (key instanceof String) {
335: return getBeanProperty(context, target, (String) key);
336: }
337: } else if (target instanceof Package) {
338: return ((Property) target).get(((String) key).intern(),
339: context);
340: } else if (target instanceof Property) {
341: return ((Property) target).get((String) key, context);
342: } else if (target instanceof Map) {
343: return ((Map) target).get(key);
344: } else if (target instanceof Context) {
345: return ((Context) target).get(((String) key).intern());
346: } else if (target instanceof Generator) {
347: if (key instanceof Number) {
348: return generateNth((Generator) target, ((Number) key)
349: .intValue(), context);
350: } else if (key instanceof PnutsFunction) {
351: return filterGenerator((Generator) target,
352: (PnutsFunction) key, context);
353: }
354: } else {
355: if (key instanceof PnutsFunction) {
356: if (target instanceof Collection) {
357: return filterGenerator((Collection) target,
358: (PnutsFunction) key, context);
359: } else if ((target instanceof int[])
360: || (target instanceof byte[])
361: || (target instanceof short[])
362: || (target instanceof char[])
363: || (target instanceof long[])
364: || (target instanceof float[])
365: || (target instanceof double[])
366: || (target instanceof boolean[])) {
367: return filterGenerator((Object) target,
368: (PnutsFunction) key, context);
369: }
370: } else if (key instanceof String) {
371: return getBeanProperty(context, target, (String) key);
372: } else if (key instanceof Number) {
373: if (target instanceof List) {
374: return ((List) target).get(((Number) key)
375: .intValue());
376: } else if (target instanceof String) {
377: return new Character(((String) target)
378: .charAt(((Number) key).intValue()));
379: } else if (target instanceof int[]) {
380: return new Integer(((int[]) target)[((Number) key)
381: .intValue()]);
382: } else if (target instanceof byte[]) {
383: return new Byte(((byte[]) target)[((Number) key)
384: .intValue()]);
385: } else if (target instanceof char[]) {
386: return new Character(
387: ((char[]) target)[((Number) key).intValue()]);
388: } else if (target instanceof float[]) {
389: return new Float(((float[]) target)[((Number) key)
390: .intValue()]);
391: } else if (target instanceof double[]) {
392: return new Double(
393: ((double[]) target)[((Number) key)
394: .intValue()]);
395: } else if (target instanceof boolean[]) {
396: return Boolean
397: .valueOf(((boolean[]) target)[((Number) key)
398: .intValue()]);
399: } else if (target instanceof long[]) {
400: return new Long(((long[]) target)[((Number) key)
401: .intValue()]);
402: } else if (target instanceof short[]) {
403: return new Short(((short[]) target)[((Number) key)
404: .intValue()]);
405: }
406: }
407: }
408: throw new IllegalArgumentException(String.valueOf(key));
409: }
410:
411: public void setElement(Context context, Object target, Object key,
412: Object expr) {
413: if (target instanceof Object[]) {
414: Object[] array = (Object[]) target;
415: int idx = ((Number) key).intValue();
416: if (idx < 0 && idx >= -array.length) {
417: idx += array.length;
418: }
419: array[idx] = expr;
420: } else if (target instanceof Indexed) {
421: if (key instanceof Number) {
422: ((Indexed) target).set(((Number) key).intValue(), expr);
423: } else if (key instanceof String) {
424: setBeanProperty(context, target, (String) key, expr);
425: } else {
426: throw new IllegalArgumentException(String.valueOf(key));
427: }
428: } else if (target instanceof Package) {
429: ((Property) target).set(((String) key).intern(), expr,
430: context);
431: } else if (target instanceof Property) {
432: ((Property) target).set((String) key, expr, context);
433: } else if (target instanceof Map) {
434: ((Map) target).put(key, expr);
435: } else if (target instanceof Context) {
436: ((Context) target).set(((String) key).intern(), expr);
437: } else {
438: int idx = ((Number) key).intValue();
439: if (target instanceof List) {
440: List list = (List) target;
441: int sz = list.size();
442: if (idx < 0 && idx >= -sz) {
443: idx += sz;
444: }
445: list.set(idx, expr);
446: } else if (target instanceof int[]) {
447: int[] array = (int[]) target;
448: int sz = array.length;
449: if (idx < 0 && idx >= -sz) {
450: idx += sz;
451: }
452: array[idx] = ((Number) expr).intValue();
453: } else if (target instanceof byte[]) {
454: byte[] array = (byte[]) target;
455: int sz = array.length;
456: if (idx < 0 && idx >= -sz) {
457: idx += sz;
458: }
459: array[idx] = ((Number) expr).byteValue();
460: } else if (target instanceof char[]) {
461: char[] array = (char[]) target;
462: int sz = array.length;
463: if (idx < 0 && idx >= -sz) {
464: idx += sz;
465: }
466: array[idx] = ((Character) expr).charValue();
467: } else if (target instanceof float[]) {
468: float[] array = (float[]) target;
469: int sz = array.length;
470: if (idx < 0 && idx >= -sz) {
471: idx += sz;
472: }
473: array[idx] = ((Number) expr).floatValue();
474: } else if (target instanceof double[]) {
475: double[] array = (double[]) target;
476: int sz = array.length;
477: if (idx < 0 && idx >= -sz) {
478: idx += sz;
479: }
480: array[idx] = ((Number) expr).doubleValue();
481: } else if (target instanceof boolean[]) {
482: boolean[] array = (boolean[]) target;
483: int sz = array.length;
484: if (idx < 0 && idx >= -sz) {
485: idx += sz;
486: }
487: array[idx] = ((Boolean) expr).booleanValue();
488: } else if (target instanceof long[]) {
489: long[] array = (long[]) target;
490: int sz = array.length;
491: if (idx < 0 && idx >= -sz) {
492: idx += sz;
493: }
494: array[idx] = ((Number) expr).longValue();
495: } else if (target instanceof short[]) {
496: short[] array = (short[]) target;
497: int sz = array.length;
498: if (idx < 0 && idx >= -sz) {
499: idx += sz;
500: }
501: array[idx] = ((Number) expr).shortValue();
502: } else {
503: if (key instanceof String) {
504: setBeanProperty(context, target, (String) key, expr);
505: } else {
506: throw new IllegalArgumentException(String
507: .valueOf(key));
508: }
509: }
510: }
511: }
512:
513: static void setElements(Object target, int from, int to, Object expr) {
514: if (target instanceof Object[]) {
515: Object[] array = (Object[]) target;
516: for (int i = from; i <= to; i++) {
517: array[i] = expr;
518: }
519: } else if (target instanceof Indexed) {
520: Indexed indexed = (Indexed) target;
521: for (int i = from; i <= to; i++) {
522: indexed.set(i, expr);
523: }
524: } else if (target instanceof List) {
525: List list = (List) target;
526: for (int i = from; i <= to; i++) {
527: list.set(i, expr);
528: }
529: } else if (target instanceof int[]) {
530: int[] array = (int[]) target;
531: for (int i = from; i <= to; i++) {
532: array[i] = ((Number) expr).intValue();
533: }
534: } else if (target instanceof byte[]) {
535: byte[] array = (byte[]) target;
536: for (int i = from; i <= to; i++) {
537: array[i] = ((Number) expr).byteValue();
538: }
539: } else if (target instanceof char[]) {
540: char[] array = (char[]) target;
541: for (int i = from; i <= to; i++) {
542: array[i] = ((Character) expr).charValue();
543: }
544: } else if (target instanceof float[]) {
545: float[] array = (float[]) target;
546: for (int i = from; i <= to; i++) {
547: array[i] = ((Number) expr).floatValue();
548: }
549: } else if (target instanceof double[]) {
550: double[] array = (double[]) target;
551: for (int i = from; i <= to; i++) {
552: array[i] = ((Number) expr).doubleValue();
553: }
554: } else if (target instanceof boolean[]) {
555: boolean[] array = (boolean[]) target;
556: for (int i = from; i <= to; i++) {
557: array[i] = ((Boolean) expr).booleanValue();
558: }
559: } else if (target instanceof long[]) {
560: long[] array = (long[]) target;
561: for (int i = from; i <= to; i++) {
562: array[i] = ((Number) expr).longValue();
563: }
564: } else if (target instanceof short[]) {
565: short[] array = (short[]) target;
566: for (int i = from; i <= to; i++) {
567: array[i] = ((Number) expr).shortValue();
568: }
569: } else {
570: for (int i = from; i <= to; i++) {
571: Array.set(target, i, expr);
572: }
573: }
574: }
575:
576: /**
577: * Defines the semantices of an expression like:
578: *
579: * <pre>
580: * target[idx1..idx2]
581: * </pre>
582: *
583: * @param context
584: * the context
585: * @param target
586: * the target object
587: * @param idx1
588: * the start index
589: * @param idx2
590: * the end index, which can be null
591: */
592: public Object getRange(Context context, Object target, Object idx1,
593: Object idx2) {
594: int from = ((Number) idx1).intValue();
595: int to = -1;
596: if (idx2 != null) {
597: to = ((Number) idx2).intValue();
598: }
599: if (target instanceof String) {
600: String s = (String) target;
601: int len = s.length();
602: if (from > len - 1) {
603: return "";
604: }
605: if (idx2 != null) {
606: if (from > to || to < 0) {
607: return "";
608: }
609: if (from < 0) {
610: from = 0;
611: }
612: if (to > len - 1) {
613: to = len - 1;
614: }
615: return s.substring(from, to + 1);
616: } else {
617: if (from < 0) {
618: from = 0;
619: }
620: return s.substring(from);
621: }
622: } else if (Runtime.isArray(target)) {
623: Class c = target.getClass().getComponentType();
624: int len = Runtime.getArrayLength(target);
625: if (from > len - 1) {
626: return Array.newInstance(c, 0);
627: }
628: if (idx2 == null) {
629: to = len - 1;
630: } else {
631: if (from > to || to < 0) {
632: return Array.newInstance(c, 0);
633: }
634: if (to > len - 1) {
635: to = len - 1;
636: }
637: }
638: if (from < 0) {
639: from = 0;
640: }
641: int size = to - from + 1;
642: if (size < 0) {
643: size = 0;
644: } else if (from + size > len) {
645: size = len - from;
646: }
647: Object ret = Array.newInstance(c, size);
648: if (size > 0) {
649: System.arraycopy(target, from, ret, 0, size);
650: }
651: return ret;
652: } else if (target instanceof List) {
653: List list = (List) target;
654: try {
655: int size = list.size();
656: if (from < 0) {
657: from = 0;
658: } else if (from > size) {
659: from = size;
660: }
661: if (idx2 == null) {
662: to = size;
663: } else {
664: if (from > to || to < 0) {
665: to = from;
666: } else {
667: to++;
668: if (to > size) {
669: to = size;
670: }
671: }
672: }
673: } catch (Exception e) {
674: // allow size() to throw an exception
675: }
676: return list.subList(from, to);
677: } else if (target instanceof Generator) {
678: if (idx2 != null) {
679: if (from > to || to < 0) {
680: from = -1;
681: to = -1;
682: } else if (from < 0) {
683: from = 0;
684: }
685: } else {
686: to = -1;
687: if (from < 0) {
688: from = 0;
689: }
690: }
691: return new Runtime.RangeGenerator((Generator) target, from,
692: to);
693: } else {
694: throw new PnutsException("illegal.type",
695: new Object[] { target }, context);
696: }
697: }
698:
699: /**
700: * Defines the semantices of an expression like:
701: * <p>
702: *
703: * <pre>
704: * target[idx1..idx2] = expr
705: * </pre>
706: *
707: * </p>
708: *
709: * @param context
710: * the context in which the assignment is done
711: * @param target
712: * the target object
713: * @param idx1
714: * the start index
715: * @param idx2
716: * the end index, which can be null
717: * @param expr
718: * the new value of the indexed element
719: */
720: public Object setRange(Context context, Object target, Object idx1,
721: Object idx2, Object expr) {
722: int from = ((Number) idx1).intValue();
723: int to = -1;
724: if (idx2 != null) {
725: to = ((Number) idx2).intValue();
726: if (from > to || to < 0) {
727: return target;
728: }
729: }
730: if (target instanceof String) {
731: StringBuffer s = new StringBuffer((String) target);
732: int len = s.length();
733: if (from > len - 1) {
734: return target;
735: }
736: if (idx2 == null) {
737: to = len - 1;
738: } else {
739: if (to > len - 1) {
740: to = len - 1;
741: }
742: }
743: if (from < 0) {
744: from = 0;
745: }
746: if (expr instanceof Character) {
747: char c = ((Character) expr).charValue();
748: for (int i = from; i < to + 1; i++) {
749: s.setCharAt(i, c);
750: }
751: } else {
752: replace(s, from, to + 1, String.valueOf(expr));
753: }
754: String val = s.toString();
755: return val;
756: } else if (Runtime.isArray(target)) {
757: int len = Runtime.getArrayLength(target);
758: if (from > len - 1) {
759: return target;
760: }
761: if (idx2 == null) {
762: to = len - 1;
763: } else {
764: if (to > len - 1) {
765: to = len - 1;
766: }
767: }
768: if (from < 0) {
769: from = 0;
770: }
771: int size = to - from + 1;
772: if (from + size > len) {
773: size = len - from;
774: }
775: if (target instanceof char[] && expr instanceof String) {
776: String str = (String) expr;
777: int end = str.length();
778: if (end > to - from + 1) {
779: end = to - from + 1;
780: }
781: str.getChars(0, end, (char[]) target, from);
782: } else {
783: setElements(target, from, to, expr);
784: }
785: return target;
786: } else if (target instanceof List) {
787: List list = (List) target;
788: try {
789: int size = list.size();
790: if (from < 0) {
791: from = 0;
792: } else if (from > size) {
793: from = size;
794: }
795: if (idx2 == null) {
796: to = size;
797: } else {
798: if (from > to || to < 0) {
799: to = from;
800: } else {
801: to++;
802: if (to > size) {
803: to = size;
804: }
805: }
806: }
807: } catch (Exception e) {
808: // allow size() to throw an exception
809: }
810: for (int i = from; i < to; i++) {
811: list.set(i, expr);
812: }
813: return target;
814: } else {
815: throw new PnutsException("illegal.type", Runtime.NO_PARAM,
816: context);
817: }
818: }
819:
820: Object reInvoke(IllegalAccessException t, final Method method,
821: Object target, Object[] args)
822: throws IllegalAccessException, InvocationTargetException {
823: if (DEBUG) {
824: System.out.println("setAccessible " + method.getName());
825: }
826: method.setAccessible(true);
827: return method.invoke(target, args);
828: }
829:
830: void replace(StringBuffer buf, int from, int to, String str) {
831: buf.replace(from, to, str);
832: }
833:
834: protected ClassLoader getInitialClassLoader() {
835: return Thread.currentThread().getContextClassLoader();
836: }
837:
838: Generator fieldGenerator(final Generator g, String name,
839: Context context) {
840: final String fieldName = name;
841: return new Generator() {
842: public Object apply(final PnutsFunction closure,
843: final Context context) {
844: g.apply(new PnutsFunction() {
845: protected Object exec(Object[] args, Context ctx) {
846: closure
847: .call(new Object[] { Runtime.getField(
848: context, args[0], fieldName) },
849: context);
850: return null;
851: }
852: }, context);
853: return null;
854: }
855: };
856: }
857:
858: static Generator filterGenerator(Object array, PnutsFunction pred,
859: Context context) {
860: // return filterGenerator((Object[])Runtime.transform(Object.class, array), pred,context);
861: return filterGenerator((Object[]) Runtime.transform(
862: Object.class, array, context), pred, context);
863: }
864:
865: static Generator filterGenerator(final Object[] array,
866: final PnutsFunction pred, final Context context) {
867: return new Generator() {
868: public Object apply(final PnutsFunction closure,
869: final Context c) {
870: int len = array.length;
871: for (int i = 0; i < len; i++) {
872: Object[] args = new Object[] { array[i] };
873: if (((Boolean) pred.call(args, /*context*/c))
874: .booleanValue()) {
875: closure.call(args, c);
876: }
877: }
878: return null;
879: }
880: };
881: }
882:
883: static Generator filterGenerator(final Collection collection,
884: final PnutsFunction pred, final Context context) {
885: return new Generator() {
886: public Object apply(final PnutsFunction closure,
887: final Context c) {
888: for (Iterator it = collection.iterator(); it.hasNext();) {
889: Object[] args = new Object[] { it.next() };
890: if (((Boolean) pred.call(args, c)).booleanValue()) {
891: closure.call(args, c);
892: }
893: }
894: return null;
895: }
896: };
897: }
898:
899: static Generator filterGenerator(final Generator g,
900: final PnutsFunction pred, Context context) {
901: return new Generator() {
902: public Object apply(final PnutsFunction closure,
903: final Context context) {
904: g.apply(new PnutsFunction() {
905: protected Object exec(Object[] args, Context ctx) {
906: if (((Boolean) pred.call(args, ctx))
907: .booleanValue()) {
908: closure.call(args, ctx);
909: }
910: return null;
911: }
912: }, context);
913: return null;
914: }
915: };
916: }
917:
918: static Object generateNth(Generator g, int idx, Context context) {
919: if (idx < 0) {
920: return null;
921: }
922: Counter c = new Counter(idx);
923: try {
924: g.apply(c, context);
925: } catch (CounterEscape esc) {
926: return esc.getValue();
927: }
928: return null;
929: }
930:
931: static class Counter extends PnutsFunction {
932: int n;
933:
934: Counter(int n) {
935: this .n = n;
936: }
937:
938: protected Object exec(Object[] args, Context c) {
939: if (n > 0) {
940: n--;
941: } else {
942: throw new CounterEscape(args[0]);
943: }
944: return null;
945: }
946: }
947:
948: static class CounterEscape extends Escape {
949: Object value;
950:
951: CounterEscape(Object value) {
952: this .value = value;
953: }
954:
955: public Object getValue() {
956: return value;
957: }
958: }
959: }
|