ValuesFilter.java 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (c) 2001, 2003 Per M.A. Bothner and Brainfood Inc.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.xquery.util;
  4. import gnu.lists.*;
  5. import gnu.mapping.*;
  6. import gnu.bytecode.*;
  7. import gnu.expr.*;
  8. import gnu.kawa.xml.*;
  9. import gnu.math.IntNum;
  10. import gnu.kawa.functions.AddOp;
  11. import gnu.kawa.functions.NumberCompare;
  12. import gnu.kawa.functions.ValuesMap;
  13. /* #ifdef use:java.lang.invoke */
  14. import java.lang.invoke.*;
  15. /* #else */
  16. // import gnu.mapping.CallContext.MethodHandle;
  17. /* #endif */
  18. public class ValuesFilter extends MethodProc implements Inlineable
  19. {
  20. /** 'F' if following a ForwardStep; 'R' if following a ReverseStep;
  21. * 'P' if following a PrimaryExpr. */
  22. char kind;
  23. static final MethodHandle applyToConsumer =
  24. Procedure.lookupApplyHandle(ValuesFilter.class, "applyToConsumer");
  25. public ValuesFilter(char kind) {
  26. this.kind = kind;
  27. this.applyToConsumerMethod = applyToConsumer;
  28. setProperty(Procedure.validateApplyKey,
  29. "gnu.xquery.util.CompileMisc:validateApplyValuesFilter");
  30. }
  31. public static ValuesFilter get (char kind)
  32. {
  33. if (kind == 'F') return forwardFilter;
  34. else if (kind == 'R') return reverseFilter;
  35. else return exprFilter;
  36. }
  37. /** 2 if last() is needed (implicit if kind=='R');
  38. * 1 if position() is needed;
  39. * 0 otherwise. */
  40. int last_or_position_needed = 2;
  41. public int numArgs() { return 0x2002; }
  42. static public boolean matches(Object result, long count)
  43. {
  44. if (result instanceof Values)
  45. result = ((Values) result).canonicalize();
  46. if (result instanceof Number)
  47. {
  48. if (result instanceof IntNum)
  49. return IntNum.compare((IntNum) result, count) == 0;
  50. if (result instanceof Double || result instanceof Float
  51. || result instanceof gnu.math.DFloNum)
  52. return ((Number) result).doubleValue() == (double) count;
  53. if (result instanceof Long || result instanceof Integer
  54. || result instanceof Short || result instanceof Byte)
  55. return count == ((Number) result).longValue();
  56. // Non-optimal for BigDecimal and BigInteger. FIXME.
  57. return NumberCompare.applyWithPromotion(Compare.TRUE_IF_EQU,
  58. IntNum.make(count),
  59. result);
  60. }
  61. return BooleanValue.booleanValue(result);
  62. }
  63. public static Object applyToConsumer(Procedure proc, CallContext ctx) throws Throwable {
  64. char kind = ((ValuesFilter) proc).kind;
  65. Object arg = ctx.getNextArg();
  66. Procedure filter = (Procedure) ctx.getNextArg();
  67. Consumer out = ctx.consumer;
  68. Values values;
  69. if (kind != 'P')
  70. {
  71. SortedNodes nodes = new SortedNodes();
  72. Values.writeValues(arg, nodes);
  73. values = nodes;
  74. }
  75. else if (arg instanceof Values)
  76. values = (Values) arg;
  77. else
  78. {
  79. IntNum one = IntNum.one();
  80. if (matches(filter.apply3(arg, one, one), 1))
  81. out.writeObject(arg);
  82. return null;
  83. }
  84. int count = values.size();
  85. int it = 0;
  86. IntNum countObj = IntNum.make(count);
  87. // The filter procedures takes 3 arguments if last() is needed,
  88. // or 2 arguments if validateApply has determined we don't need last().
  89. int pmax = filter.maxArgs();
  90. for (int i = 0; i < count; i++)
  91. {
  92. it = values.nextPos(it);
  93. Object dot = values.getPosPrevious(it);
  94. int pos = kind == 'R' ? (count - i) : (i + 1);
  95. IntNum posObj = IntNum.make(pos);
  96. Object pred_res = pmax == 2 ? filter.apply2(dot, posObj)
  97. : filter.apply3(dot, posObj, countObj);
  98. if (matches(pred_res, pos))
  99. out.writeObject(dot);
  100. }
  101. return null;
  102. }
  103. public void compile (ApplyExp exp, Compilation comp, Target target)
  104. {
  105. Expression[] args = exp.getArgs();
  106. Expression exp1 = args[0];
  107. Expression exp2 = args[1];
  108. if (target instanceof IgnoreTarget)
  109. {
  110. exp1.compile(comp, target);
  111. exp2.compile(comp, target);
  112. return;
  113. }
  114. if (! (exp2 instanceof LambdaExp))
  115. {
  116. ApplyExp.compile(exp, comp, target);
  117. return;
  118. }
  119. if (! (target instanceof ConsumerTarget))
  120. {
  121. ConsumerTarget.compileUsingConsumer(exp, comp, target);
  122. return;
  123. }
  124. // At this point, we don't depend on last().
  125. LambdaExp lexp2 = (LambdaExp) exp2;
  126. ValuesMap.compileInlined(lexp2, exp1, 1, matchesMethod, comp, target);
  127. }
  128. public Type getReturnType (Expression[] args)
  129. {
  130. // Needlessly conservative, but it shouldn't matter, since this
  131. // shouldn't be called if the ApplyExp.setType has been done.
  132. return Type.pointer_type;
  133. }
  134. public static final ValuesFilter forwardFilter = new ValuesFilter('F');
  135. public static final ValuesFilter reverseFilter = new ValuesFilter('R');
  136. public static final ValuesFilter exprFilter = new ValuesFilter('P');
  137. public static final ClassType typeValuesFilter
  138. = ClassType.make("gnu.xquery.util.ValuesFilter");
  139. public static final Method matchesMethod
  140. = typeValuesFilter.getDeclaredMethod("matches", 2);
  141. }