KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > functions > ValuesMap


1 // Copyright (c) 2001, 2003, 2004 Per M.A. Bothner and Brainfood Inc.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.kawa.functions;
5 import gnu.lists.*;
6 import gnu.mapping.*;
7 import gnu.bytecode.*;
8 import gnu.expr.*;
9 import gnu.math.IntNum;
10
11 /** Map a function over a value sequence, yielding a new sequence.
12  * Normally, the function takes one argument, the item in the sequence.
13  * If startCounter is non-negative, a position index is also passed.
14  * Used to implement XQuery's 'for' form.
15  */

16
17 public class ValuesMap extends MethodProc implements CanInline, Inlineable
18 {
19   public static final ValuesMap valuesMap = new ValuesMap(-1);
20   public static final ValuesMap valuesMapWithPos = new ValuesMap(1);
21
22   private ValuesMap (int startCounter)
23   {
24     this.startCounter = startCounter;
25   }
26
27   /** If non-negative also define a counter variable.
28    * Used for XQuery's 'at' clause in a FLWOR expression. */

29   private final int startCounter;
30
31   public int numArgs() { return 0x2002; }
32
33   public void apply (CallContext ctx) throws Throwable JavaDoc
34   {
35     Procedure proc = (Procedure) ctx.getNextArg();
36     Consumer out = ctx.consumer;
37     Object JavaDoc val = ctx.getNextArg();
38     Procedure.checkArgCount(proc, 1);
39     if (val instanceof Values)
40       {
41     int ipos = 0;
42     int count = startCounter;
43     Values values = (Values) val;
44     while ((ipos = values.nextPos(ipos)) != 0)
45       {
46         Object JavaDoc v = values.getPosPrevious(ipos);
47         if (startCounter >= 0)
48           proc.check2(v, IntNum.make(count++), ctx);
49         else
50           proc.check1(v, ctx);
51         ctx.runUntilDone();
52       }
53       }
54     else
55       {
56     if (startCounter >= 0)
57       proc.check2(val, IntNum.make(startCounter), ctx);
58     else
59       proc.check1(val, ctx);
60     ctx.runUntilDone();
61       }
62   }
63
64   /** If we can inline, return LambdaExp for first arg; otherwise null. */
65   private LambdaExp canInline (ApplyExp exp)
66   {
67     Expression[] args = exp.getArgs();
68     Expression arg0;
69     // FIXME Could if needed wrap expr in LambdaExp:
70
if (args.length == 2 && (arg0 = args[0]) instanceof LambdaExp)
71       {
72     LambdaExp lexp = (LambdaExp) arg0;
73     if (lexp.min_args == lexp.max_args
74         && lexp.min_args == (startCounter >= 0 ? 2 : 1))
75       return lexp;
76       }
77     return null;
78   }
79
80   public Expression inline (ApplyExp exp, ExpWalker walker)
81   {
82     LambdaExp lexp = canInline(exp);
83     if (lexp != null)
84       {
85     lexp.setInlineOnly(true);
86     lexp.returnContinuation = exp;
87       }
88     return exp;
89   }
90
91   public void compile (ApplyExp exp, Compilation comp, Target target)
92   {
93     LambdaExp lambda = canInline(exp);
94     if (lambda == null)
95       {
96     ApplyExp.compile(exp, comp, target);
97     return;
98       }
99     Expression[] args = exp.getArgs();
100     if (! (target instanceof IgnoreTarget
101        || target instanceof ConsumerTarget
102        || target instanceof SeriesTarget))
103       {
104     ConsumerTarget.compileUsingConsumer(exp, comp, target);
105     return;
106       }
107     Expression vals = args[1];
108     compileInlined(lambda, vals, startCounter, null, comp, target);
109   }
110
111   public static void compileInlined(LambdaExp lambda, Expression vals,
112                                     int startCounter, Method matchesMethod,
113                                     Compilation comp, Target target)
114   {
115     Declaration param = lambda.firstDecl();
116     CodeAttr code = comp.getCode();
117     SeriesTarget starget = new SeriesTarget();
118     starget.scope = code.pushScope();
119     Variable counter;
120     Declaration counterDecl;
121     if (startCounter >= 0)
122       {
123     counter = starget.scope.addVariable(code, Type.int_type, "position");
124     code.emitPushInt(startCounter);
125     code.emitStore(counter);
126         counterDecl = new Declaration(counter);
127       }
128     else
129       {
130         counter = null;
131         counterDecl = null;
132       }
133     starget.function = new Label(code);
134     if (target instanceof SeriesTarget)
135       starget.done = ((SeriesTarget) target).done;
136     else
137       starget.done = new Label(code);
138     // If the param Declaration is captured, then it gets messy initializing
139
// it. So just cheat and create a helper variable.
140
if (param.isSimple())
141       param.allocateVariable(code);
142     else
143       param = new Declaration(code.addLocal(param.getType(), param.getName()));
144     starget.param = param;
145     Type retAddrType = Type.pointer_type;
146     Variable retAddr = code.addLocal(retAddrType);
147     vals.compileWithPosition(comp, starget);
148
149     starget.function.define(code);
150     code.pushType(retAddrType);
151     code.emitStore(retAddr);
152     Expression[] args;
153     if (startCounter >= 0)
154       {
155     args = new Expression[] { new ReferenceExp(param),
156                                   new ReferenceExp(counterDecl) };
157       }
158     else
159       args = new Expression[] { new ReferenceExp(param) };
160     Expression app = new ApplyExp(lambda, args);
161     if (matchesMethod != null)
162       {
163         // Major kludge - used by ValuesFilter.
164
if (app.getType().getImplementationType() != Type.boolean_type)
165           app = new ApplyExp(matchesMethod,
166                              new Expression[] {
167                                app,
168                                new ReferenceExp(counterDecl) });
169         app = new IfExp(app, new ReferenceExp(param), QuoteExp.voidExp);
170       }
171     if (target instanceof SeriesTarget)
172       {
173         SeriesTarget atarget = (SeriesTarget) target;
174         Label done = atarget.done;
175         atarget.done = null;
176         app.compile(comp, target);
177         atarget.done = done;
178       }
179     else
180       app.compile(comp, target);
181     if (startCounter >= 0)
182       {
183     code.emitInc(counter, (short) 1);
184       }
185     code.emitRet(retAddr);
186     code.popScope();
187     if (! (target instanceof SeriesTarget))
188       starget.done.define(code);
189   }
190
191   public Type getReturnType (Expression[] args)
192   {
193     return Type.pointer_type;
194   }
195 }
196
Popular Tags