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: RelationalExpr.java,v 1.2.4.1 2005/09/12 11:05:00 pvedula Exp $
22   */
23  
24  package com.sun.org.apache.xalan.internal.xsltc.compiler;
25  
26  import com.sun.org.apache.bcel.internal.generic.BranchInstruction;
27  import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
28  import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
29  import com.sun.org.apache.bcel.internal.generic.InstructionList;
30  import com.sun.org.apache.bcel.internal.generic.PUSH;
31  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
32  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
34  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
35  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
36  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
37  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
38  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
39  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
40  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
41  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
42  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
43  import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
44  import com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;
45  
46  /**
47   * @author Jacek Ambroziak
48   * @author Santiago Pericas-Geertsen
49   */
50  final class RelationalExpr extends Expression {
51  
52      private int _op;
53      private Expression _left, _right;
54  
55      public RelationalExpr(int op, Expression left, Expression right) {
56          _op = op;
57          (_left = left).setParent(this);
58          (_right = right).setParent(this);
59      }
60  
61      public void setParser(Parser parser) {
62          super.setParser(parser);
63          _left.setParser(parser);
64          _right.setParser(parser);
65      }
66  
67      /**
68       * Returns true if this expressions contains a call to position(). This is
69       * needed for context changes in node steps containing multiple predicates.
70       */
71      public boolean hasPositionCall() {
72          if (_left.hasPositionCall()) return true;
73          if (_right.hasPositionCall()) return true;
74          return false;
75      }
76  
77      /**
78       * Returns true if this expressions contains a call to last()
79       */
80      public boolean hasLastCall() {
81              return (_left.hasLastCall() || _right.hasLastCall());
82      }
83  
84      public boolean hasReferenceArgs() {
85          return _left.getType() instanceof ReferenceType ||
86              _right.getType() instanceof ReferenceType;
87      }
88  
89      public boolean hasNodeArgs() {
90          return _left.getType() instanceof NodeType ||
91              _right.getType() instanceof NodeType;
92      }
93  
94      public boolean hasNodeSetArgs() {
95          return _left.getType() instanceof NodeSetType ||
96              _right.getType() instanceof NodeSetType;
97      }
98  
99      public Type typeCheck(SymbolTable stable) throws TypeCheckError {
100         Type tleft = _left.typeCheck(stable);
101         Type tright = _right.typeCheck(stable);
102 
103         //bug fix # 2838, cast to reals if both are result tree fragments
104         if (tleft instanceof ResultTreeType &&
105             tright instanceof ResultTreeType )
106         {
107             _right = new CastExpr(_right, Type.Real);
108             _left = new CastExpr(_left, Type.Real);
109             return _type = Type.Boolean;
110         }
111 
112         // If one is of reference type, then convert the other too
113         if (hasReferenceArgs()) {
114             Type type = null;
115             Type typeL = null;
116             Type typeR = null;
117             if (tleft instanceof ReferenceType) {
118                 if (_left instanceof VariableRefBase) {
119                     VariableRefBase ref = (VariableRefBase)_left;
120                     VariableBase var = ref.getVariable();
121                     typeL = var.getType();
122                 }
123             }
124             if (tright instanceof ReferenceType) {
125                 if (_right instanceof VariableRefBase) {
126                     VariableRefBase ref = (VariableRefBase)_right;
127                     VariableBase var = ref.getVariable();
128                     typeR = var.getType();
129                 }
130             }
131             // bug fix # 2838
132             if (typeL == null)
133                 type = typeR;
134             else if (typeR == null)
135                 type = typeL;
136             else {
137                 type = Type.Real;
138             }
139             if (type == null) type = Type.Real;
140 
141             _right = new CastExpr(_right, type);
142             _left = new CastExpr(_left, type);
143             return _type = Type.Boolean;
144         }
145 
146         if (hasNodeSetArgs()) {
147             // Ensure that the node-set is the left argument
148             if (tright instanceof NodeSetType) {
149                 final Expression temp = _right; _right = _left; _left = temp;
150         _op = (_op == Operators.GT) ? Operators.LT :
151             (_op == Operators.LT) ? Operators.GT :
152             (_op == Operators.GE) ? Operators.LE : Operators.GE;
153                 tright = _right.getType();
154             }
155 
156             // Promote nodes to node sets
157             if (tright instanceof NodeType) {
158                 _right = new CastExpr(_right, Type.NodeSet);
159             }
160             // Promote integer to doubles to have fewer compares
161             if (tright instanceof IntType) {
162                 _right = new CastExpr(_right, Type.Real);
163             }
164             // Promote result-trees to strings
165             if (tright instanceof ResultTreeType) {
166                 _right = new CastExpr(_right, Type.String);
167             }
168             return _type = Type.Boolean;
169         }
170 
171         // In the node-boolean case, convert node to boolean first
172         if (hasNodeArgs()) {
173             if (tleft instanceof BooleanType) {
174                 _right = new CastExpr(_right, Type.Boolean);
175                 tright = Type.Boolean;
176             }
177             if (tright instanceof BooleanType) {
178                 _left = new CastExpr(_left, Type.Boolean);
179                 tleft = Type.Boolean;
180             }
181         }
182 
183         // Lookup the table of primops to find the best match
184     MethodType ptype = lookupPrimop(stable, Operators.getOpNames(_op),
185                 new MethodType(Type.Void, tleft, tright));
186 
187         if (ptype != null) {
188             Type arg1 = (Type) ptype.argsType().elementAt(0);
189             if (!arg1.identicalTo(tleft)) {
190                 _left = new CastExpr(_left, arg1);
191             }
192             Type arg2 = (Type) ptype.argsType().elementAt(1);
193             if (!arg2.identicalTo(tright)) {
194                 _right = new CastExpr(_right, arg1);
195             }
196             return _type = ptype.resultType();
197         }
198         throw new TypeCheckError(this);
199     }
200 
201     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
202         if (hasNodeSetArgs() || hasReferenceArgs()) {
203             final ConstantPoolGen cpg = classGen.getConstantPool();
204             final InstructionList il = methodGen.getInstructionList();
205 
206             // Call compare() from the BasisLibrary
207             _left.translate(classGen, methodGen);
208             _left.startIterator(classGen, methodGen);
209             _right.translate(classGen, methodGen);
210             _right.startIterator(classGen, methodGen);
211 
212             il.append(new PUSH(cpg, _op));
213             il.append(methodGen.loadDOM());
214 
215             int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "compare",
216                                          "("
217                                          + _left.getType().toSignature()
218                                          + _right.getType().toSignature()
219                                          + "I"
220                                          + DOM_INTF_SIG
221                                          + ")Z");
222             il.append(new INVOKESTATIC(index));
223         }
224         else {
225             translateDesynthesized(classGen, methodGen);
226             synthesize(classGen, methodGen);
227         }
228     }
229 
230     public void translateDesynthesized(ClassGenerator classGen,
231                                        MethodGenerator methodGen) {
232         if (hasNodeSetArgs() || hasReferenceArgs()) {
233             translate(classGen, methodGen);
234             desynthesize(classGen, methodGen);
235         }
236         else {
237             BranchInstruction bi = null;
238             final InstructionList il = methodGen.getInstructionList();
239 
240             _left.translate(classGen, methodGen);
241             _right.translate(classGen, methodGen);
242 
243             // TODO: optimize if one of the args is 0
244 
245             boolean tozero = false;
246             Type tleft = _left.getType();
247 
248             if (tleft instanceof RealType) {
249         il.append(tleft.CMP(_op == Operators.LT || _op == Operators.LE));
250                 tleft = Type.Int;
251                 tozero = true;
252             }
253 
254             switch (_op) {
255         case Operators.LT:
256                 bi = tleft.GE(tozero);
257                 break;
258 
259         case Operators.GT:
260                 bi = tleft.LE(tozero);
261                 break;
262 
263         case Operators.LE:
264                 bi = tleft.GT(tozero);
265                 break;
266 
267         case Operators.GE:
268                 bi = tleft.LT(tozero);
269                 break;
270 
271             default:
272                 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_RELAT_OP_ERR,this);
273                 getParser().reportError(Constants.FATAL, msg);
274             }
275 
276             _falseList.add(il.append(bi));              // must be backpatched
277         }
278     }
279 
280     public String toString() {
281         return Operators.getOpNames(_op) + '(' + _left + ", " + _right + ')';
282     }
283 }