RelativeStep.java 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright (c) 2003 Per M.A. Bothner.
  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.*;
  11. import gnu.kawa.reflect.OccurrenceType;
  12. /* #ifdef use:java.lang.invoke */
  13. import java.lang.invoke.*;
  14. /* #else */
  15. // import gnu.mapping.CallContext.MethodHandle;
  16. /* #endif */
  17. /** Implements XPath path expression.
  18. * The XPath expression E1/E2 is compiled into:
  19. * (relative-step E1 (lambda (dot position last) E2)).
  20. */
  21. public class RelativeStep extends MethodProc implements Inlineable
  22. {
  23. static final MethodHandle applyToConsumer =
  24. Procedure.lookupApplyHandle(RelativeStep.class, "applyToConsumer");
  25. public static final RelativeStep relativeStep = new RelativeStep();
  26. RelativeStep() {
  27. this.applyToConsumerMethod = applyToConsumer;
  28. setProperty(Procedure.validateApplyKey,
  29. "gnu.xquery.util.CompileMisc:validateApplyRelativeStep");
  30. }
  31. public int numArgs() { return 0x2002; }
  32. public static Object applyToConsumer(Procedure proc, CallContext ctx) throws Throwable {
  33. Object arg = ctx.getNextArg();
  34. Object next = ctx.getNextArg();
  35. Procedure sproc = (Procedure) next;
  36. Consumer out = ctx.consumer;
  37. IntNum countObj;
  38. Nodes values;
  39. if (arg instanceof Nodes)
  40. values = (Nodes) arg;
  41. else
  42. {
  43. values = new Nodes();
  44. Values.writeValues(arg, values);
  45. }
  46. int count = values.size();
  47. int it = 0;
  48. countObj = IntNum.make(count);
  49. RelativeStepFilter filter = new RelativeStepFilter(out);
  50. for (int pos = 1; pos <= count; pos++)
  51. {
  52. it = values.nextPos(it);
  53. Object dot = values.getPosPrevious(it);
  54. ctx.setupApply(sproc, dot, IntNum.make(pos), countObj);
  55. Values.writeValues(ctx.runUntilValue(), filter);
  56. }
  57. filter.finish();
  58. return null;
  59. }
  60. public void compile (ApplyExp exp, Compilation comp, Target target)
  61. {
  62. Expression[] args = exp.getArgs();
  63. Expression exp1 = args[0];
  64. Expression exp2 = args[1];
  65. if (target instanceof IgnoreTarget)
  66. {
  67. exp1.compile(comp, target);
  68. exp2.compile(comp, target);
  69. return;
  70. }
  71. Type rtype = exp.getTypeRaw();
  72. if (rtype == null) // should never happen
  73. rtype = Type.pointer_type;
  74. Type rtypePrime = OccurrenceType.itemPrimeType(rtype);
  75. int nodeCompare = NodeType.anyNodeTest.compare(rtypePrime);
  76. // 'A' - atomic; 'N' - nodes; 'S' - pre-sorted nodes; ' ' - unknown.
  77. char expectedKind;
  78. if (nodeCompare >= 0)
  79. expectedKind = 'N';
  80. else if (nodeCompare == -3)
  81. expectedKind = 'A';
  82. else
  83. expectedKind = ' ';
  84. TreeScanner step = extractStep(exp2);
  85. if (step != null)
  86. {
  87. Type type1 = exp1.getType();
  88. if (step instanceof ChildAxis
  89. || step instanceof AttributeAxis
  90. || step instanceof SelfAxis)
  91. {
  92. if (type1 instanceof NodeSetType
  93. || (expectedKind == 'N'
  94. && OccurrenceType.itemCountIsZeroOrOne(exp1.getType())))
  95. expectedKind = 'S';
  96. /*
  97. // It's presumably more efficient to sort the argument
  98. // nodes rather than the result nodes. FIXME
  99. else
  100. {
  101. exp1 = SortNodes(exp1);
  102. expectedKind = 'S';
  103. }
  104. */
  105. }
  106. }
  107. if (! (target instanceof ConsumerTarget))
  108. {
  109. ConsumerTarget.compileUsingConsumer(exp, comp, target);
  110. return;
  111. }
  112. CodeAttr code = comp.getCode();
  113. Target mtarget;
  114. Scope scope = code.pushScope();
  115. Variable mconsumer;
  116. Variable tconsumer;
  117. ClassType mclass;
  118. if (expectedKind == 'A' || expectedKind == 'S')
  119. {
  120. mtarget = target;
  121. mclass = null;
  122. mconsumer = null;
  123. tconsumer = null;
  124. }
  125. else
  126. {
  127. // We need a helper consumer.
  128. Method initMethod;
  129. if (expectedKind == 'N')
  130. {
  131. mclass = ClassType.make("gnu.kawa.xml.SortedNodes");
  132. initMethod = mclass.getDeclaredMethod("<init>", 0);
  133. }
  134. else
  135. {
  136. mclass = ClassType.make("gnu.xquery.util.RelativeStepFilter");
  137. initMethod = mclass.getDeclaredMethod("<init>", 1);
  138. }
  139. mconsumer = scope.addVariable(code, mclass, null);
  140. mtarget = new ConsumerTarget(mconsumer);
  141. code.emitNew(mclass);
  142. code.emitDup(mclass);
  143. tconsumer = ((ConsumerTarget) target).getConsumerVariable();
  144. if (expectedKind != 'N')
  145. code.emitLoad(tconsumer);
  146. code.emitInvoke(initMethod);
  147. code.emitStore(mconsumer);
  148. }
  149. ValuesMap.compileInlined((LambdaExp) exp2, exp1, 1, null, comp, mtarget);
  150. // Now finish up from the helper consumer.
  151. if (expectedKind == 'N')
  152. {
  153. code.emitLoad(mconsumer);
  154. code.emitLoad(tconsumer);
  155. code.emitInvokeStatic(Compilation.typeValues
  156. .getDeclaredMethod("writeValues", 2));
  157. }
  158. else if (expectedKind == ' ')
  159. {
  160. code.emitLoad(mconsumer);
  161. code.emitInvoke(mclass.getDeclaredMethod("finish", 0));
  162. }
  163. code.popScope();
  164. }
  165. public Type getReturnType (Expression[] args)
  166. {
  167. // Needlessly convervative, but it shouldn't matter, since this
  168. // shouldn't be called if the ApplyExp.setType has been done.
  169. return Type.pointer_type;
  170. }
  171. public static TreeScanner extractStep (Expression exp)
  172. {
  173. for (;;)
  174. {
  175. if (! (exp instanceof ApplyExp))
  176. return null;
  177. ApplyExp aexp = (ApplyExp) exp;
  178. Expression func = aexp.getFunction();
  179. if (func instanceof QuoteExp)
  180. {
  181. Object value = ((QuoteExp) func).getValue();
  182. if (value instanceof TreeScanner)
  183. return (TreeScanner) value;
  184. // This doesn't work, if we've already inlined ValuesFilter. FIXME
  185. if (value instanceof ValuesFilter)
  186. {
  187. exp = aexp.getArgs()[0];
  188. continue;
  189. }
  190. }
  191. return null;
  192. }
  193. }
  194. }