001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: RelationalExpr.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.BranchInstruction; 025 import org.apache.bcel.generic.ConstantPoolGen; 026 import org.apache.bcel.generic.INVOKESTATIC; 027 import org.apache.bcel.generic.InstructionList; 028 import org.apache.bcel.generic.PUSH; 029 import org.apache.xalan.xsltc.compiler.util.BooleanType; 030 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 031 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 032 import org.apache.xalan.xsltc.compiler.util.IntType; 033 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 034 import org.apache.xalan.xsltc.compiler.util.MethodType; 035 import org.apache.xalan.xsltc.compiler.util.NodeSetType; 036 import org.apache.xalan.xsltc.compiler.util.NodeType; 037 import org.apache.xalan.xsltc.compiler.util.RealType; 038 import org.apache.xalan.xsltc.compiler.util.ReferenceType; 039 import org.apache.xalan.xsltc.compiler.util.ResultTreeType; 040 import org.apache.xalan.xsltc.compiler.util.Type; 041 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 042 import org.apache.xalan.xsltc.runtime.Operators; 043 044 /** 045 * @author Jacek Ambroziak 046 * @author Santiago Pericas-Geertsen 047 */ 048 final class RelationalExpr extends Expression { 049 050 private int _op; 051 private Expression _left, _right; 052 053 public RelationalExpr(int op, Expression left, Expression right) { 054 _op = op; 055 (_left = left).setParent(this); 056 (_right = right).setParent(this); 057 } 058 059 public void setParser(Parser parser) { 060 super.setParser(parser); 061 _left.setParser(parser); 062 _right.setParser(parser); 063 } 064 065 /** 066 * Returns true if this expressions contains a call to position(). This is 067 * needed for context changes in node steps containing multiple predicates. 068 */ 069 public boolean hasPositionCall() { 070 if (_left.hasPositionCall()) return true; 071 if (_right.hasPositionCall()) return true; 072 return false; 073 } 074 075 /** 076 * Returns true if this expressions contains a call to last() 077 */ 078 public boolean hasLastCall() { 079 return (_left.hasLastCall() || _right.hasLastCall()); 080 } 081 082 public boolean hasReferenceArgs() { 083 return _left.getType() instanceof ReferenceType || 084 _right.getType() instanceof ReferenceType; 085 } 086 087 public boolean hasNodeArgs() { 088 return _left.getType() instanceof NodeType || 089 _right.getType() instanceof NodeType; 090 } 091 092 public boolean hasNodeSetArgs() { 093 return _left.getType() instanceof NodeSetType || 094 _right.getType() instanceof NodeSetType; 095 } 096 097 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 098 Type tleft = _left.typeCheck(stable); 099 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 }