KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > xquery > util > ValuesFilter


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

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.AddOp;
12 import gnu.kawa.functions.NumberCompare;
13 import gnu.kawa.functions.ValuesMap;
14
15 public class ValuesFilter extends MethodProc implements CanInline, Inlineable
16 {
17   /** 'F' if following a ForwardStep; 'R' if following a ReverseStep;
18    * 'P' if following a PrimaryExpr. */

19   char kind;
20
21   public ValuesFilter (char kind)
22   {
23     this.kind = kind;
24   }
25
26   public static ValuesFilter get (char kind)
27   {
28     if (kind == 'F') return forwardFilter;
29     else if (kind == 'R') return reverseFilter;
30     else return exprFilter;
31   }
32
33   /** 2 if last() is needed (implicit if kind=='R');
34    * 1 if position() is needed;
35    * 0 otherwise. */

36   int last_or_position_needed = 2;
37
38   public int numArgs() { return 0x2002; }
39
40   static public boolean matches(Object JavaDoc result, long count)
41   {
42     if (result instanceof Values)
43       result = ((Values) result).canonicalize();
44     if (result instanceof Number JavaDoc)
45       {
46         if (result instanceof IntNum)
47           return IntNum.compare((IntNum) result, count) == 0;
48         if (result instanceof Double JavaDoc || result instanceof Float JavaDoc
49             || result instanceof gnu.math.DFloNum)
50           return ((Number JavaDoc) result).doubleValue() == (double) count;
51         if (result instanceof Long JavaDoc || result instanceof Integer JavaDoc
52             || result instanceof Short JavaDoc || result instanceof Byte JavaDoc)
53           return count == ((Number JavaDoc) result).longValue();
54         // Non-optimal for BigDecimal and BigInteger. FIXME.
55
return NumberCompare.applyWithPromotion(Compare.TRUE_IF_EQU,
56                                                 IntNum.make(count),
57                                                 result);
58       }
59     return BooleanValue.booleanValue(result);
60   }
61
62   public void apply (CallContext ctx) throws Throwable JavaDoc
63   {
64     Object JavaDoc arg = ctx.getNextArg();
65     Procedure proc = (Procedure) ctx.getNextArg();
66     Consumer out = ctx.consumer;
67     Values values;
68     if (kind != 'P')
69       {
70     SortedNodes nodes = new SortedNodes();
71     Values.writeValues(arg, nodes);
72     values = nodes;
73       }
74     else if (arg instanceof Values)
75       values = (Values) arg;
76     else
77       {
78     IntNum one = IntNum.one();
79     if (matches(proc.apply3(arg, one, one), 1))
80       out.writeObject(arg);
81     return;
82       }
83     int count = values.size();
84     int it = 0;
85     IntNum countObj = IntNum.make(count);
86     // The filter procedures takes 3 arguments is last() is needed,
87
// or 2 arguments if inline has determined we don't need last().
88
int pmax = proc.maxArgs();
89     for (int i = 0; i < count; i++)
90       {
91     it = values.nextPos(it);
92     Object JavaDoc dot = values.getPosPrevious(it);
93     int pos = kind == 'R' ? (count - i) : (i + 1);
94     IntNum posObj = IntNum.make(pos);
95     Object JavaDoc pred_res = pmax == 2 ? proc.apply2(dot, posObj)
96           : proc.apply3(dot, posObj, countObj);
97     if (matches(pred_res, pos))
98       out.writeObject(dot);
99       }
100     return;
101   }
102
103   public Expression inline (ApplyExp exp, ExpWalker walker)
104   {
105     Expression[] args = exp.getArgs();
106     Expression exp2 = args[1];
107     LambdaExp lexp2;
108     if (! (exp2 instanceof LambdaExp)
109     || (lexp2 = (LambdaExp) exp2).min_args != 3
110     || lexp2.max_args != 3)
111       return exp;
112
113     exp.setType(args[0].getType());
114
115     Compilation parser = walker.getCompilation();
116
117     Declaration dotArg = lexp2.firstDecl();
118     Declaration posArg = dotArg.nextDecl();
119     Declaration lastArg = posArg.nextDecl();
120
121     lexp2.setInlineOnly(true);
122     lexp2.returnContinuation = exp;
123
124     // Splice out lastArg
125
lexp2.remove(posArg, lastArg);
126     lexp2.min_args = 2;
127     lexp2.max_args = 2;
128
129     if (! lastArg.getCanRead() && kind != 'R')
130       {
131         // Don't need to do anything more - lastArg is not needed.
132
return exp;
133       }
134
135     parser.letStart();
136     Expression seq = args[0];
137     Type seqType;
138     Method sizeMethod;
139     if (kind == 'P')
140       {
141         seqType = seq.getType();
142         sizeMethod = Compilation.typeValues.getDeclaredMethod("countValues", 1);
143       }
144     else
145       {
146         seqType = SortNodes.typeSortedNodes;
147         seq = new ApplyExp(SortNodes.sortNodes, new Expression [] {seq});
148         sizeMethod = CoerceNodes.typeNodes.getDeclaredMethod("size", 0);
149       }
150     Declaration sequence = parser.letVariable("sequence", seqType, seq);
151     parser.letEnter();
152
153     Expression pred = lexp2.body;
154     if (kind == 'R')
155       {
156         Declaration posIncoming = new Declaration(null, Type.int_type);
157     Expression init
158       = new ApplyExp(AddOp.$Mn,
159              new Expression[] {
160                new ReferenceExp(lastArg),
161                new ReferenceExp(posIncoming)});
162     init
163       = new ApplyExp(AddOp.$Pl,
164              new Expression[] {
165                init,
166                new QuoteExp(IntNum.one())});
167         LetExp let = new LetExp(new Expression[] { init });
168         lexp2.replaceFollowing(dotArg, posIncoming);
169         let.add(posArg);
170         let.body = pred;
171         pred = let;
172       }
173
174     Type predType = lexp2.body.getType();
175     if (predType != XDataType.booleanType) // Overly conservative, but simple.
176
pred = new ApplyExp(matchesMethod,
177                           new Expression[] { pred,
178                                              new ReferenceExp(posArg) });
179     pred = new IfExp(pred,
180                      new ReferenceExp(dotArg),
181                      QuoteExp.voidExp);
182     lexp2.body = pred;
183
184     ApplyExp doMap
185       = new ApplyExp(ValuesMap.valuesMapWithPos,
186              new Expression[] { lexp2,
187                     new ReferenceExp(sequence) });
188     doMap.setType(dotArg.getType());
189     lexp2.returnContinuation = doMap;
190
191     Expression lastInit = new ApplyExp(sizeMethod,
192                                        new Expression[] {
193                                          new ReferenceExp(sequence)});
194
195     LetExp let2 = new LetExp(new Expression[] { lastInit });
196     let2.add(lastArg);
197     let2.body = ValuesMap.valuesMapWithPos.inline(doMap, walker);
198
199
200     return parser.letDone(let2);
201   }
202
203   public void compile (ApplyExp exp, Compilation comp, Target target)
204   {
205     Expression[] args = exp.getArgs();
206     Expression exp1 = args[0];
207     Expression exp2 = args[1];
208     if (target instanceof IgnoreTarget)
209       {
210         exp1.compile(comp, target);
211         exp2.compile(comp, target);
212         return;
213       }
214     if (! (exp2 instanceof LambdaExp))
215       {
216         ApplyExp.compile(exp, comp, target);
217         return;
218       }
219
220     if (! (target instanceof ConsumerTarget))
221       {
222     ConsumerTarget.compileUsingConsumer(exp, comp, target);
223     return;
224       }
225     // Should also handle SeriesTarget - later? FIXME
226

227     // At this point, we don't depend on last().
228
LambdaExp lexp2 = (LambdaExp) exp2;
229     ValuesMap.compileInlined(lexp2, exp1, 1, matchesMethod, comp, target);
230   }
231
232   public Type getReturnType (Expression[] args)
233   {
234     // Needlessly conservative, but it shouldn't matter, since this
235
// shouldn't be called if the ApplyExp.setType has been done.
236
return Type.pointer_type;
237   }
238
239   public static final ValuesFilter forwardFilter = new ValuesFilter('F');
240   public static final ValuesFilter reverseFilter = new ValuesFilter('R');
241   public static final ValuesFilter exprFilter = new ValuesFilter('P');
242   public static final ClassType typeValuesFilter
243     = ClassType.make("gnu.xquery.util.ValuesFilter");
244   public static final Method matchesMethod
245     = typeValuesFilter.getDeclaredMethod("matches", 2);
246 }
247
Popular Tags