View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: EqualityExpr.java,v 1.2.4.1 2005/09/12 10:16:52 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import com.sun.org.apache.bcel.internal.generic.BranchHandle;
27  import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
28  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
29  import com.sun.org.apache.bcel.internal.generic.GOTO;
30  import com.sun.org.apache.bcel.internal.generic.IFEQ;
31  import com.sun.org.apache.bcel.internal.generic.IFNE;
32  import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
33  import com.sun.org.apache.bcel.internal.generic.IF_ICMPNE;
34  import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
35  import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
36  import com.sun.org.apache.bcel.internal.generic.InstructionList;
37  import com.sun.org.apache.bcel.internal.generic.PUSH;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
42  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
43  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
44  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NumberType;
45  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
46  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
47  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
48  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringType;
49  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
50  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
51  import com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;
52  
53  /**
54   * @author Jacek Ambroziak
55   * @author Santiago Pericas-Geertsen
56   * @author Morten Jorgensen
57   * @author Erwin Bolwidt <ejb@klomp.org>
58   */
59  final class EqualityExpr extends Expression {
60  
61      private final int _op;
62      private Expression _left;
63      private Expression _right;
64  
65      public EqualityExpr(int op, Expression left, Expression right) {
66          _op = op;
67          (_left = left).setParent(this);
68          (_right = right).setParent(this);
69      }
70  
71      public void setParser(Parser parser) {
72          super.setParser(parser);
73          _left.setParser(parser);
74          _right.setParser(parser);
75      }
76  
77      public String toString() {
78          return Operators.getOpNames(_op) + '(' + _left + ", " + _right + ')';
79      }
80  
81      public Expression getLeft() {
82          return _left;
83      }
84  
85      public Expression getRight() {
86          return _right;
87      }
88  
89      public boolean getOp() {
90          return (_op != Operators.NE);
91      }
92  
93      /**
94       * Returns true if this expressions contains a call to position(). This is
95       * needed for context changes in node steps containing multiple predicates.
96       */
97      public boolean hasPositionCall() {
98          if (_left.hasPositionCall()) return true;
99          if (_right.hasPositionCall()) return true;
100         return false;
101     }
102 
103     public boolean hasLastCall() {
104         if (_left.hasLastCall()) return true;
105         if (_right.hasLastCall()) return true;
106         return false;
107     }
108 
109     private void swapArguments() {
110         final Expression temp = _left;
111         _left = _right;
112         _right = temp;
113     }
114 
115     /**
116      * Typing rules: see XSLT Reference by M. Kay page 345.
117      */
118     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
119         final Type tleft = _left.typeCheck(stable);
120         final Type tright = _right.typeCheck(stable);
121 
122         if (tleft.isSimple() && tright.isSimple()) {
123             if (tleft != tright) {
124                 if (tleft instanceof BooleanType) {
125                     _right = new CastExpr(_right, Type.Boolean);
126                 }
127                 else if (tright instanceof BooleanType) {
128                     _left = new CastExpr(_left, Type.Boolean);
129                 }
130                 else if (tleft instanceof NumberType ||
131                          tright instanceof NumberType) {
132                     _left = new CastExpr(_left, Type.Real);
133                     _right = new CastExpr(_right, Type.Real);
134                 }
135                 else {          // both compared as strings
136                     _left = new CastExpr(_left,   Type.String);
137                     _right = new CastExpr(_right, Type.String);
138                 }
139             }
140         }
141         else if (tleft instanceof ReferenceType) {
142             _right = new CastExpr(_right, Type.Reference);
143         }
144         else if (tright instanceof ReferenceType) {
145             _left = new CastExpr(_left, Type.Reference);
146         }
147         // the following 2 cases optimize @attr|.|.. = 'string'
148         else if (tleft instanceof NodeType && tright == Type.String) {
149             _left = new CastExpr(_left, Type.String);
150         }
151         else if (tleft == Type.String && tright instanceof NodeType) {
152             _right = new CastExpr(_right, Type.String);
153         }
154         // optimize node/node
155         else if (tleft instanceof NodeType && tright instanceof NodeType) {
156             _left = new CastExpr(_left, Type.String);
157             _right = new CastExpr(_right, Type.String);
158         }
159         else if (tleft instanceof NodeType && tright instanceof NodeSetType) {
160             // compare(Node, NodeSet) will be invoked
161         }
162         else if (tleft instanceof NodeSetType && tright instanceof NodeType) {
163             swapArguments();    // for compare(Node, NodeSet)
164         }
165         else {
166             // At least one argument is of type node, node-set or result-tree
167 
168             // Promote an expression of type node to node-set
169             if (tleft instanceof NodeType) {
170                 _left = new CastExpr(_left, Type.NodeSet);
171             }
172             if (tright instanceof NodeType) {
173                 _right = new CastExpr(_right, Type.NodeSet);
174             }
175 
176             // If one arg is a node-set then make it the left one
177             if (tleft.isSimple() ||
178                 tleft instanceof ResultTreeType &&
179                 tright instanceof NodeSetType) {
180                 swapArguments();
181             }
182 
183             // Promote integers to doubles to have fewer compares
184             if (_right.getType() instanceof IntType) {
185                 _right = new CastExpr(_right, Type.Real);
186             }
187         }
188         return _type = Type.Boolean;
189     }
190 
191     public void translateDesynthesized(ClassGenerator classGen,
192                                        MethodGenerator methodGen) {
193         final Type tleft = _left.getType();
194         final InstructionList il = methodGen.getInstructionList();
195 
196         if (tleft instanceof BooleanType) {
197             _left.translate(classGen, methodGen);
198             _right.translate(classGen, methodGen);
199         _falseList.add(il.append(_op == Operators.EQ ?
200                                      (BranchInstruction)new IF_ICMPNE(null) :
201                                      (BranchInstruction)new IF_ICMPEQ(null)));
202         }
203         else if (tleft instanceof NumberType) {
204             _left.translate(classGen, methodGen);
205             _right.translate(classGen, methodGen);
206 
207             if (tleft instanceof RealType) {
208                 il.append(DCMPG);
209         _falseList.add(il.append(_op == Operators.EQ ?
210                                          (BranchInstruction)new IFNE(null) :
211                                          (BranchInstruction)new IFEQ(null)));
212             }
213             else {
214             _falseList.add(il.append(_op == Operators.EQ ?
215                                          (BranchInstruction)new IF_ICMPNE(null) :
216                                          (BranchInstruction)new IF_ICMPEQ(null)));
217             }
218         }
219         else {
220             translate(classGen, methodGen);
221             desynthesize(classGen, methodGen);
222         }
223     }
224 
225     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
226         final ConstantPoolGen cpg = classGen.getConstantPool();
227         final InstructionList il = methodGen.getInstructionList();
228 
229         final Type tleft = _left.getType();
230         Type tright = _right.getType();
231 
232         if (tleft instanceof BooleanType || tleft instanceof NumberType) {
233             translateDesynthesized(classGen, methodGen);
234             synthesize(classGen, methodGen);
235             return;
236         }
237 
238         if (tleft instanceof StringType) {
239             final int equals = cpg.addMethodref(STRING_CLASS,
240                                                 "equals",
241                                                 "(" + OBJECT_SIG +")Z");
242             _left.translate(classGen, methodGen);
243             _right.translate(classGen, methodGen);
244             il.append(new INVOKEVIRTUAL(equals));
245 
246         if (_op == Operators.NE) {
247                 il.append(ICONST_1);
248                 il.append(IXOR);                        // not x <-> x xor 1
249             }
250             return;
251         }
252 
253         BranchHandle truec, falsec;
254 
255         if (tleft instanceof ResultTreeType) {
256             if (tright instanceof BooleanType) {
257                 _right.translate(classGen, methodGen);
258         if (_op == Operators.NE) {
259                     il.append(ICONST_1);
260                     il.append(IXOR); // not x <-> x xor 1
261                 }
262                 return;
263             }
264 
265             if (tright instanceof RealType) {
266                 _left.translate(classGen, methodGen);
267                 tleft.translateTo(classGen, methodGen, Type.Real);
268                 _right.translate(classGen, methodGen);
269 
270                 il.append(DCMPG);
271         falsec = il.append(_op == Operators.EQ ?
272                                    (BranchInstruction) new IFNE(null) :
273                                    (BranchInstruction) new IFEQ(null));
274                 il.append(ICONST_1);
275                 truec = il.append(new GOTO(null));
276                 falsec.setTarget(il.append(ICONST_0));
277                 truec.setTarget(il.append(NOP));
278                 return;
279             }
280 
281             // Next, result-tree/string and result-tree/result-tree comparisons
282 
283             _left.translate(classGen, methodGen);
284             tleft.translateTo(classGen, methodGen, Type.String);
285             _right.translate(classGen, methodGen);
286 
287             if (tright instanceof ResultTreeType) {
288                 tright.translateTo(classGen, methodGen, Type.String);
289             }
290 
291             final int equals = cpg.addMethodref(STRING_CLASS,
292                                                 "equals",
293                                                 "(" +OBJECT_SIG+ ")Z");
294             il.append(new INVOKEVIRTUAL(equals));
295 
296         if (_op == Operators.NE) {
297                 il.append(ICONST_1);
298                 il.append(IXOR);                        // not x <-> x xor 1
299             }
300             return;
301         }
302 
303         if (tleft instanceof NodeSetType && tright instanceof BooleanType) {
304             _left.translate(classGen, methodGen);
305             _left.startIterator(classGen, methodGen);
306             Type.NodeSet.translateTo(classGen, methodGen, Type.Boolean);
307             _right.translate(classGen, methodGen);
308 
309             il.append(IXOR); // x != y <-> x xor y
310         if (_op == Operators.EQ) {
311                 il.append(ICONST_1);
312                 il.append(IXOR); // not x <-> x xor 1
313             }
314             return;
315         }
316 
317         if (tleft instanceof NodeSetType && tright instanceof StringType) {
318             _left.translate(classGen, methodGen);
319             _left.startIterator(classGen, methodGen); // needed ?
320             _right.translate(classGen, methodGen);
321             il.append(new PUSH(cpg, _op));
322             il.append(methodGen.loadDOM());
323             final int cmp = cpg.addMethodref(BASIS_LIBRARY_CLASS,
324                                              "compare",
325                                              "("
326                                              + tleft.toSignature()
327                                              + tright.toSignature()
328                                              + "I"
329                                              + DOM_INTF_SIG
330                                              + ")Z");
331             il.append(new INVOKESTATIC(cmp));
332             return;
333         }
334 
335         // Next, node-set/t for t in {real, string, node-set, result-tree}
336         _left.translate(classGen, methodGen);
337         _left.startIterator(classGen, methodGen);
338         _right.translate(classGen, methodGen);
339         _right.startIterator(classGen, methodGen);
340 
341         // Cast a result tree to a string to use an existing compare
342         if (tright instanceof ResultTreeType) {
343             tright.translateTo(classGen, methodGen, Type.String);
344             tright = Type.String;
345         }
346 
347         // Call the appropriate compare() from the BasisLibrary
348         il.append(new PUSH(cpg, _op));
349         il.append(methodGen.loadDOM());
350 
351         final int compare = cpg.addMethodref(BASIS_LIBRARY_CLASS,
352                                              "compare",
353                                              "("
354                                              + tleft.toSignature()
355                                              + tright.toSignature()
356                                              + "I"
357                                              + DOM_INTF_SIG
358                                              + ")Z");
359         il.append(new INVOKESTATIC(compare));
360     }
361 }