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