KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > EqualityExpr


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: EqualityExpr.java,v 1.14 2004/02/16 22:24:29 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import org.apache.bcel.generic.BranchHandle;
23 import org.apache.bcel.generic.BranchInstruction;
24 import org.apache.bcel.generic.ConstantPoolGen;
25 import org.apache.bcel.generic.GOTO;
26 import org.apache.bcel.generic.IFEQ;
27 import org.apache.bcel.generic.IFNE;
28 import org.apache.bcel.generic.IF_ICMPEQ;
29 import org.apache.bcel.generic.IF_ICMPNE;
30 import org.apache.bcel.generic.INVOKESTATIC;
31 import org.apache.bcel.generic.INVOKEVIRTUAL;
32 import org.apache.bcel.generic.InstructionList;
33 import org.apache.bcel.generic.PUSH;
34 import org.apache.xalan.xsltc.compiler.util.BooleanType;
35 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
36 import org.apache.xalan.xsltc.compiler.util.IntType;
37 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
38 import org.apache.xalan.xsltc.compiler.util.NodeSetType;
39 import org.apache.xalan.xsltc.compiler.util.NodeType;
40 import org.apache.xalan.xsltc.compiler.util.NumberType;
41 import org.apache.xalan.xsltc.compiler.util.RealType;
42 import org.apache.xalan.xsltc.compiler.util.ReferenceType;
43 import org.apache.xalan.xsltc.compiler.util.ResultTreeType;
44 import org.apache.xalan.xsltc.compiler.util.StringType;
45 import org.apache.xalan.xsltc.compiler.util.Type;
46 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
47 import org.apache.xalan.xsltc.runtime.Operators;
48
49 /**
50  * @author Jacek Ambroziak
51  * @author Santiago Pericas-Geertsen
52  * @author Morten Jorgensen
53  * @author Erwin Bolwidt <ejb@klomp.org>
54  */

55 final class EqualityExpr extends Expression implements Operators {
56     private final int _op;
57     private Expression _left;
58     private Expression _right;
59         
60     public EqualityExpr(int op, Expression left, Expression right) {
61     _op = op;
62     (_left = left).setParent(this);
63     (_right = right).setParent(this);
64     }
65
66     public void setParser(Parser parser) {
67     super.setParser(parser);
68     _left.setParser(parser);
69     _right.setParser(parser);
70     }
71     
72     public String JavaDoc toString() {
73     return Operators.names[_op] + '(' + _left + ", " + _right + ')';
74     }
75
76     public Expression getLeft() {
77     return _left;
78     }
79
80     public Expression getRight() {
81     return _right;
82     }
83
84     public boolean getOp() {
85     return (_op != Operators.NE);
86     }
87
88     /**
89      * Returns true if this expressions contains a call to position(). This is
90      * needed for context changes in node steps containing multiple predicates.
91      */

92     public boolean hasPositionCall() {
93     if (_left.hasPositionCall()) return true;
94     if (_right.hasPositionCall()) return true;
95     return false;
96     }
97
98     public boolean hasLastCall() {
99     if (_left.hasLastCall()) return true;
100     if (_right.hasLastCall()) return true;
101     return false;
102     }
103
104     private void swapArguments() {
105     final Expression temp = _left;
106     _left = _right;
107     _right = temp;
108     }
109
110     /**
111      * Typing rules: see XSLT Reference by M. Kay page 345.
112      */

113     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
114     final Type tleft = _left.typeCheck(stable);
115     final Type tright = _right.typeCheck(stable);
116
117     if (tleft.isSimple() && tright.isSimple()) {
118         if (tleft != tright) {
119         if (tleft instanceof BooleanType) {
120             _right = new CastExpr(_right, Type.Boolean);
121         }
122         else if (tright instanceof BooleanType) {
123             _left = new CastExpr(_left, Type.Boolean);
124         }
125         else if (tleft instanceof NumberType ||
126              tright instanceof NumberType) {
127             _left = new CastExpr(_left, Type.Real);
128             _right = new CastExpr(_right, Type.Real);
129         }
130         else { // both compared as strings
131
_left = new CastExpr(_left, Type.String);
132             _right = new CastExpr(_right, Type.String);
133         }
134         }
135     }
136     else if (tleft instanceof ReferenceType) {
137         _right = new CastExpr(_right, Type.Reference);
138     }
139     else if (tright instanceof ReferenceType) {
140         _left = new CastExpr(_left, Type.Reference);
141     }
142     // the following 2 cases optimize @attr|.|.. = 'string'
143
else if (tleft instanceof NodeType && tright == Type.String) {
144         _left = new CastExpr(_left, Type.String);
145     }
146     else if (tleft == Type.String && tright instanceof NodeType) {
147         _right = new CastExpr(_right, Type.String);
148     }
149     // optimize node/node
150
else if (tleft instanceof NodeType && tright instanceof NodeType) {
151         _left = new CastExpr(_left, Type.String);
152         _right = new CastExpr(_right, Type.String);
153     }
154     else if (tleft instanceof NodeType && tright instanceof NodeSetType) {
155         // compare(Node, NodeSet) will be invoked
156
}
157     else if (tleft instanceof NodeSetType && tright instanceof NodeType) {
158         swapArguments(); // for compare(Node, NodeSet)
159
}
160     else {
161         // At least one argument is of type node, node-set or result-tree
162

163         // Promote an expression of type node to node-set
164
if (tleft instanceof NodeType) {
165         _left = new CastExpr(_left, Type.NodeSet);
166         }
167         if (tright instanceof NodeType) {
168         _right = new CastExpr(_right, Type.NodeSet);
169         }
170
171         // If one arg is a node-set then make it the left one
172
if (tleft.isSimple() ||
173         tleft instanceof ResultTreeType &&
174         tright instanceof NodeSetType) {
175         swapArguments();
176         }
177
178         // Promote integers to doubles to have fewer compares
179
if (_right.getType() instanceof IntType) {
180         _right = new CastExpr(_right, Type.Real);
181         }
182     }
183     return _type = Type.Boolean;
184     }
185
186     public void translateDesynthesized(ClassGenerator classGen,
187                        MethodGenerator methodGen) {
188     final Type tleft = _left.getType();
189     final InstructionList il = methodGen.getInstructionList();
190
191     if (tleft instanceof BooleanType) {
192         _left.translate(classGen, methodGen);
193         _right.translate(classGen, methodGen);
194         _falseList.add(il.append(_op == Operators.EQ ?
195                      (BranchInstruction)new IF_ICMPNE(null) :
196                      (BranchInstruction)new IF_ICMPEQ(null)));
197     }
198     else if (tleft instanceof NumberType) {
199         _left.translate(classGen, methodGen);
200         _right.translate(classGen, methodGen);
201
202         if (tleft instanceof RealType) {
203         il.append(DCMPG);
204         _falseList.add(il.append(_op == Operators.EQ ?
205                      (BranchInstruction)new IFNE(null) :
206                      (BranchInstruction)new IFEQ(null)));
207         }
208         else {
209         _falseList.add(il.append(_op == Operators.EQ ?
210                      (BranchInstruction)new IF_ICMPNE(null) :
211                      (BranchInstruction)new IF_ICMPEQ(null)));
212         }
213     }
214     else {
215         translate(classGen, methodGen);
216         desynthesize(classGen, methodGen);
217     }
218     }
219
220     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
221     final ConstantPoolGen cpg = classGen.getConstantPool();
222     final InstructionList il = methodGen.getInstructionList();
223
224     final Type tleft = _left.getType();
225     Type tright = _right.getType();
226
227     if (tleft instanceof BooleanType || tleft instanceof NumberType) {
228         translateDesynthesized(classGen, methodGen);
229         synthesize(classGen, methodGen);
230         return;
231     }
232
233     if (tleft instanceof StringType) {
234         final int equals = cpg.addMethodref(STRING_CLASS,
235                         "equals",
236                         "(" + OBJECT_SIG +")Z");
237         _left.translate(classGen, methodGen);
238         _right.translate(classGen, methodGen);
239         il.append(new INVOKEVIRTUAL(equals));
240
241         if (_op == Operators.NE) {
242         il.append(ICONST_1);
243         il.append(IXOR); // not x <-> x xor 1
244
}
245         return;
246     }
247
248     BranchHandle truec, falsec;
249     
250     if (tleft instanceof ResultTreeType) {
251         if (tright instanceof BooleanType) {
252         _right.translate(classGen, methodGen);
253         if (_op == Operators.NE) {
254             il.append(ICONST_1);
255             il.append(IXOR); // not x <-> x xor 1
256
}
257         return;
258         }
259
260         if (tright instanceof RealType) {
261         _left.translate(classGen, methodGen);
262         tleft.translateTo(classGen, methodGen, Type.Real);
263         _right.translate(classGen, methodGen);
264
265         il.append(DCMPG);
266         falsec = il.append(_op == Operators.EQ ?
267                    (BranchInstruction) new IFNE(null) :
268                    (BranchInstruction) new IFEQ(null));
269         il.append(ICONST_1);
270         truec = il.append(new GOTO(null));
271         falsec.setTarget(il.append(ICONST_0));
272         truec.setTarget(il.append(NOP));
273         return;
274         }
275
276         // Next, result-tree/string and result-tree/result-tree comparisons
277

278         _left.translate(classGen, methodGen);
279         tleft.translateTo(classGen, methodGen, Type.String);
280         _right.translate(classGen, methodGen);
281
282         if (tright instanceof ResultTreeType) {
283         tright.translateTo(classGen, methodGen, Type.String);
284         }
285
286         final int equals = cpg.addMethodref(STRING_CLASS,
287                         "equals",
288                         "(" +OBJECT_SIG+ ")Z");
289         il.append(new INVOKEVIRTUAL(equals));
290
291         if (_op == Operators.NE) {
292         il.append(ICONST_1);
293         il.append(IXOR); // not x <-> x xor 1
294
}
295         return;
296     }
297
298     if (tleft instanceof NodeSetType && tright instanceof BooleanType) {
299         _left.translate(classGen, methodGen);
300         _left.startIterator(classGen, methodGen);
301         Type.NodeSet.translateTo(classGen, methodGen, Type.Boolean);
302         _right.translate(classGen, methodGen);
303
304         il.append(IXOR); // x != y <-> x xor y
305
if (_op == EQ) {
306         il.append(ICONST_1);
307         il.append(IXOR); // not x <-> x xor 1
308
}
309         return;
310     }
311
312     if (tleft instanceof NodeSetType && tright instanceof StringType) {
313         _left.translate(classGen, methodGen);
314         _left.startIterator(classGen, methodGen); // needed ?
315
_right.translate(classGen, methodGen);
316         il.append(new PUSH(cpg, _op));
317         il.append(methodGen.loadDOM());
318         final int cmp = cpg.addMethodref(BASIS_LIBRARY_CLASS,
319                          "compare",
320                          "("
321                          + tleft.toSignature()
322                          + tright.toSignature()
323                          + "I"
324                          + DOM_INTF_SIG
325                          + ")Z");
326         il.append(new INVOKESTATIC(cmp));
327         return;
328     }
329
330     // Next, node-set/t for t in {real, string, node-set, result-tree}
331
_left.translate(classGen, methodGen);
332     _left.startIterator(classGen, methodGen);
333     _right.translate(classGen, methodGen);
334     _right.startIterator(classGen, methodGen);
335
336     // Cast a result tree to a string to use an existing compare
337
if (tright instanceof ResultTreeType) {
338         tright.translateTo(classGen, methodGen, Type.String);
339         tright = Type.String;
340     }
341
342     // Call the appropriate compare() from the BasisLibrary
343
il.append(new PUSH(cpg, _op));
344     il.append(methodGen.loadDOM());
345
346     final int compare = cpg.addMethodref(BASIS_LIBRARY_CLASS,
347                          "compare",
348                          "("
349                          + tleft.toSignature()
350                          + tright.toSignature()
351                          + "I"
352                          + DOM_INTF_SIG
353                          + ")Z");
354     il.append(new INVOKESTATIC(compare));
355     }
356 }
357
Popular Tags