| 1 4 package gnu.xquery.util; 5 import gnu.lists.*; 6 import gnu.mapping.*; 7 import gnu.bytecode.*; 8 import gnu.expr.*; 9 import gnu.kawa.xml.*; 10 import gnu.math.IntNum; 11 import gnu.kawa.functions.*; 12 import gnu.kawa.reflect.OccurrenceType; 13 14 18 19 public class RelativeStep extends MethodProc implements CanInline, Inlineable 20 { 21 public static final RelativeStep relativeStep = new RelativeStep(); 22 23 public int numArgs() { return 0x2002; } 24 25 public void apply (CallContext ctx) throws Throwable  26 { 27 Object arg = ctx.getNextArg(); 28 Object next = ctx.getNextArg(); 29 Procedure proc = (Procedure) next; 30 Consumer out = ctx.consumer; 31 IntNum countObj; 32 Nodes values; 33 if (arg instanceof Nodes) 34 values = (Nodes) arg; 35 else 36 { 37 values = new Nodes(); 38 Values.writeValues(arg, values); 39 } 40 int count = values.size(); 41 int it = 0; 42 countObj = IntNum.make(count); 43 RelativeStepFilter filter = new RelativeStepFilter(out); 44 for (int pos = 1; pos <= count; pos++) 45 { 46 it = values.nextPos(it); 47 Object dot = values.getPosPrevious(it); 48 proc.check3(dot, IntNum.make(pos), countObj, ctx); 49 Values.writeValues(ctx.runUntilValue(), filter); 50 } 51 filter.finish(); 52 } 53 54 public Expression inline (ApplyExp exp, ExpWalker walker) 55 { 56 Expression[] args = exp.getArgs(); 57 Expression exp1 = args[0]; 58 Expression exp2 = args[1]; 59 LambdaExp lexp2; 60 Compilation comp = walker.getCompilation(); 61 if (! (exp2 instanceof LambdaExp) 62 || ! comp.mustCompile 65 || (lexp2 = (LambdaExp) exp2).min_args != 3 66 || lexp2.max_args != 3) 67 return exp; 68 69 lexp2.setInlineOnly(true); 70 lexp2.returnContinuation = exp; 71 72 exp2 = lexp2.body; 73 74 Declaration dotArg = lexp2.firstDecl(); 75 Declaration posArg = dotArg.nextDecl(); 76 Declaration lastArg = posArg.nextDecl(); 77 posArg.setNext(lastArg.nextDecl()); 80 lastArg.setNext(null); 81 lexp2.min_args = 2; 82 lexp2.max_args = 2; 83 84 Type type1 = exp1.getType(); 85 Type rtype = exp.getTypeRaw(); 86 Type rtypePrime; 87 int nodeCompare; 88 if (rtype == null || rtype == Type.pointer_type) 89 { 90 Type type2 = exp2.getType(); 91 rtypePrime = OccurrenceType.itemPrimeType(type2); 92 nodeCompare = NodeType.anyNodeTest.compare(rtypePrime); 93 if (nodeCompare >= 0) 94 rtype = NodeSetType.getInstance(rtypePrime); 95 else 96 rtype = OccurrenceType.getInstance(rtypePrime, 0, -1); 97 exp.setType(rtype); 98 } 99 if (lastArg.getCanRead()) 100 { 101 ClassType typeNodes = CoerceNodes.typeNodes; 102 comp.letStart(); 103 Declaration sequence 104 = comp.letVariable(null, typeNodes, 105 new ApplyExp(CoerceNodes.coerceNodes, 106 new Expression [] { exp1 })); 107 comp.letEnter(); 108 109 Method sizeMethod = typeNodes.getDeclaredMethod("size", 0); 110 Expression lastInit 111 = new ApplyExp(sizeMethod, 112 new Expression[] {new ReferenceExp(sequence)}); 113 LetExp lastLet = new LetExp(new Expression[] { lastInit }); 114 lastLet.addDeclaration(lastArg); 115 lastLet.body = new ApplyExp(exp.getFunction(), 116 new Expression[] { new ReferenceExp(sequence), 117 lexp2 }); 118 return comp.letDone(lastLet); 119 } 120 121 ApplyExp result = exp; 122 123 if (exp2 instanceof ApplyExp) 126 { 127 ApplyExp aexp2 = (ApplyExp) exp2; 128 Object proc2 = aexp2.getFunction().valueIfConstant(); 129 Expression vexp2; 130 if (proc2 instanceof ValuesFilter 131 && (vexp2 = aexp2.getArgs()[1]) instanceof LambdaExp) 132 { 133 LambdaExp lvexp2 = (LambdaExp) vexp2; 134 Declaration dot2 = lvexp2.firstDecl(); 135 Declaration pos2; 136 if (dot2 != null && (pos2 = dot2.nextDecl()) != null 137 && pos2.nextDecl() == null 138 && ! pos2.getCanRead() 139 && ClassType.make("java.lang.Number").compare(lvexp2.body.getType()) == -3) 143 { 144 exp2 = aexp2.getArg(0); 145 lexp2.body = exp2; 146 aexp2.setArg(0, exp); 147 result = aexp2; 148 } 149 } 150 } 151 if (exp1 instanceof ApplyExp && exp2 instanceof ApplyExp) 154 { 155 ApplyExp aexp1 = (ApplyExp) exp1; 156 ApplyExp aexp2 = (ApplyExp) exp2; 157 Object p1 = aexp1.getFunction().valueIfConstant(); 158 Object p2 = aexp2.getFunction().valueIfConstant(); 159 Expression exp12; 160 if (p1 == relativeStep && p2 instanceof ChildAxis 161 && aexp1.getArgCount() == 2 162 && (exp12 = aexp1.getArg(1)) instanceof LambdaExp) 163 { 164 LambdaExp lexp12 = (LambdaExp) exp12; 165 ApplyExp aexp12; 166 if (lexp12.body instanceof ApplyExp 167 && (aexp12 = (ApplyExp) lexp12.body).getFunction().valueIfConstant() == DescendantOrSelfAxis.anyNode) 168 { 169 exp.setArg(0, aexp1.getArg(0)); 170 aexp2.setFunction(new QuoteExp(DescendantAxis.make(((ChildAxis) p2).getNodePredicate()))); 171 } 172 } 173 } 174 175 return result; 176 } 177 178 public void compile (ApplyExp exp, Compilation comp, Target target) 179 { 180 Expression[] args = exp.getArgs(); 181 Expression exp1 = args[0]; 182 Expression exp2 = args[1]; 183 if (target instanceof IgnoreTarget) 184 { 185 exp1.compile(comp, target); 186 exp2.compile(comp, target); 187 return; 188 } 189 190 Type rtype = exp.getTypeRaw(); 191 if (rtype == null) rtype = Type.pointer_type; 193 Type rtypePrime = OccurrenceType.itemPrimeType(rtype); 194 int nodeCompare = NodeType.anyNodeTest.compare(rtypePrime); 195 char expectedKind; 197 if (nodeCompare >= 0) 198 expectedKind = 'N'; 199 else if (nodeCompare == -3) 200 expectedKind = 'A'; 201 else 202 expectedKind = ' '; 203 TreeScanner step = extractStep(exp2); 204 if (step != null) 205 { 206 Type type1 = exp1.getType(); 207 if (step instanceof ChildAxis 208 || step instanceof AttributeAxis 209 || step instanceof SelfAxis) 210 { 211 if (type1 instanceof NodeSetType 212 || (expectedKind == 'N' 213 && OccurrenceType.itemCountIsZeroOrOne(exp1.getType()))) 214 expectedKind = 'S'; 215 224 } 225 } 226 227 if (! (target instanceof ConsumerTarget 228 || (target instanceof SeriesTarget 229 && (expectedKind == 'A' || expectedKind == 'S')))) 230 { 231 ConsumerTarget.compileUsingConsumer(exp, comp, target); 232 return; 233 } 234 235 CodeAttr code = comp.getCode(); 236 Target mtarget; 237 Scope scope = code.pushScope(); 238 Variable mconsumer; 239 Variable tconsumer; 240 ClassType mclass; 241 242 if (expectedKind == 'A' || expectedKind == 'S') 243 { 244 mtarget = target; 245 mclass = null; 246 mconsumer = null; 247 tconsumer = null; 248 } 249 else 250 { 251 Method initMethod; 253 if (expectedKind == 'N') 254 { 255 mclass = ClassType.make("gnu.kawa.xml.SortedNodes"); 256 initMethod = mclass.getDeclaredMethod("<init>", 0); 257 } 258 else 259 { 260 mclass = ClassType.make("gnu.xquery.util.RelativeStepFilter"); 261 initMethod = mclass.getDeclaredMethod("<init>", 1); 262 } 263 mconsumer = scope.addVariable(code, mclass, null); 264 mtarget = new ConsumerTarget(mconsumer); 265 code.emitNew(mclass); 266 code.emitDup(mclass); 267 tconsumer = ((ConsumerTarget) target).getConsumerVariable(); 268 if (expectedKind != 'N') 269 code.emitLoad(tconsumer); 270 code.emitInvoke(initMethod); 271 code.emitStore(mconsumer); 272 } 273 274 ValuesMap.compileInlined((LambdaExp) exp2, exp1, 1, null, comp, mtarget); 275 276 if (expectedKind == 'N') 278 { 279 code.emitLoad(mconsumer); 280 code.emitLoad(tconsumer); 281 code.emitInvokeStatic(Compilation.typeValues 282 .getDeclaredMethod("writeValues", 2)); 283 } 284 else if (expectedKind == ' ') 285 { 286 code.emitLoad(mconsumer); 287 code.emitInvoke(mclass.getDeclaredMethod("finish", 0)); 288 } 289 290 code.popScope(); 291 } 292 293 public Type getReturnType (Expression[] args) 294 { 295 return Type.pointer_type; 298 } 299 300 public static TreeScanner extractStep (Expression exp) 301 { 302 for (;;) 303 { 304 if (! (exp instanceof ApplyExp)) 305 return null; 306 ApplyExp aexp = (ApplyExp) exp; 307 Expression func = aexp.getFunction(); 308 if (func instanceof QuoteExp) 309 { 310 Object value = ((QuoteExp) func).getValue(); 311 if (value instanceof TreeScanner) 312 return (TreeScanner) value; 313 if (value instanceof ValuesFilter) 315 { 316 exp = aexp.getArgs()[0]; 317 continue; 318 } 319 } 320 return null; 321 } 322 } 323 } 324 | Popular Tags |