286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: RelationalExpr.java,v 1.2.4.1 2005/09/12 11:05:00 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.compiler;
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.generic.BranchInstruction;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionList;
286N/Aimport com.sun.org.apache.bcel.internal.generic.PUSH;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.runtime.Operators;
286N/A
286N/A/**
286N/A * @author Jacek Ambroziak
286N/A * @author Santiago Pericas-Geertsen
286N/A */
286N/Afinal class RelationalExpr extends Expression {
286N/A
286N/A private int _op;
286N/A private Expression _left, _right;
286N/A
286N/A public RelationalExpr(int op, Expression left, Expression right) {
286N/A _op = op;
286N/A (_left = left).setParent(this);
286N/A (_right = right).setParent(this);
286N/A }
286N/A
286N/A public void setParser(Parser parser) {
286N/A super.setParser(parser);
286N/A _left.setParser(parser);
286N/A _right.setParser(parser);
286N/A }
286N/A
286N/A /**
286N/A * Returns true if this expressions contains a call to position(). This is
286N/A * needed for context changes in node steps containing multiple predicates.
286N/A */
286N/A public boolean hasPositionCall() {
286N/A if (_left.hasPositionCall()) return true;
286N/A if (_right.hasPositionCall()) return true;
286N/A return false;
286N/A }
286N/A
286N/A /**
286N/A * Returns true if this expressions contains a call to last()
286N/A */
286N/A public boolean hasLastCall() {
286N/A return (_left.hasLastCall() || _right.hasLastCall());
286N/A }
286N/A
286N/A public boolean hasReferenceArgs() {
286N/A return _left.getType() instanceof ReferenceType ||
286N/A _right.getType() instanceof ReferenceType;
286N/A }
286N/A
286N/A public boolean hasNodeArgs() {
286N/A return _left.getType() instanceof NodeType ||
286N/A _right.getType() instanceof NodeType;
286N/A }
286N/A
286N/A public boolean hasNodeSetArgs() {
286N/A return _left.getType() instanceof NodeSetType ||
286N/A _right.getType() instanceof NodeSetType;
286N/A }
286N/A
286N/A public Type typeCheck(SymbolTable stable) throws TypeCheckError {
286N/A Type tleft = _left.typeCheck(stable);
286N/A Type tright = _right.typeCheck(stable);
286N/A
286N/A //bug fix # 2838, cast to reals if both are result tree fragments
286N/A if (tleft instanceof ResultTreeType &&
286N/A tright instanceof ResultTreeType )
286N/A {
286N/A _right = new CastExpr(_right, Type.Real);
286N/A _left = new CastExpr(_left, Type.Real);
286N/A return _type = Type.Boolean;
286N/A }
286N/A
286N/A // If one is of reference type, then convert the other too
286N/A if (hasReferenceArgs()) {
286N/A Type type = null;
286N/A Type typeL = null;
286N/A Type typeR = null;
286N/A if (tleft instanceof ReferenceType) {
286N/A if (_left instanceof VariableRefBase) {
286N/A VariableRefBase ref = (VariableRefBase)_left;
286N/A VariableBase var = ref.getVariable();
286N/A typeL = var.getType();
286N/A }
286N/A }
286N/A if (tright instanceof ReferenceType) {
286N/A if (_right instanceof VariableRefBase) {
286N/A VariableRefBase ref = (VariableRefBase)_right;
286N/A VariableBase var = ref.getVariable();
286N/A typeR = var.getType();
286N/A }
286N/A }
286N/A // bug fix # 2838
286N/A if (typeL == null)
286N/A type = typeR;
286N/A else if (typeR == null)
286N/A type = typeL;
286N/A else {
286N/A type = Type.Real;
286N/A }
286N/A if (type == null) type = Type.Real;
286N/A
286N/A _right = new CastExpr(_right, type);
286N/A _left = new CastExpr(_left, type);
286N/A return _type = Type.Boolean;
286N/A }
286N/A
286N/A if (hasNodeSetArgs()) {
286N/A // Ensure that the node-set is the left argument
286N/A if (tright instanceof NodeSetType) {
286N/A final Expression temp = _right; _right = _left; _left = temp;
286N/A _op = (_op == Operators.GT) ? Operators.LT :
286N/A (_op == Operators.LT) ? Operators.GT :
286N/A (_op == Operators.GE) ? Operators.LE : Operators.GE;
286N/A tright = _right.getType();
286N/A }
286N/A
286N/A // Promote nodes to node sets
286N/A if (tright instanceof NodeType) {
286N/A _right = new CastExpr(_right, Type.NodeSet);
286N/A }
286N/A // Promote integer to doubles to have fewer compares
286N/A if (tright instanceof IntType) {
286N/A _right = new CastExpr(_right, Type.Real);
286N/A }
286N/A // Promote result-trees to strings
286N/A if (tright instanceof ResultTreeType) {
286N/A _right = new CastExpr(_right, Type.String);
286N/A }
286N/A return _type = Type.Boolean;
286N/A }
286N/A
286N/A // In the node-boolean case, convert node to boolean first
286N/A if (hasNodeArgs()) {
286N/A if (tleft instanceof BooleanType) {
286N/A _right = new CastExpr(_right, Type.Boolean);
286N/A tright = Type.Boolean;
286N/A }
286N/A if (tright instanceof BooleanType) {
286N/A _left = new CastExpr(_left, Type.Boolean);
286N/A tleft = Type.Boolean;
286N/A }
286N/A }
286N/A
286N/A // Lookup the table of primops to find the best match
286N/A MethodType ptype = lookupPrimop(stable, Operators.getOpNames(_op),
286N/A new MethodType(Type.Void, tleft, tright));
286N/A
286N/A if (ptype != null) {
286N/A Type arg1 = (Type) ptype.argsType().elementAt(0);
286N/A if (!arg1.identicalTo(tleft)) {
286N/A _left = new CastExpr(_left, arg1);
286N/A }
286N/A Type arg2 = (Type) ptype.argsType().elementAt(1);
286N/A if (!arg2.identicalTo(tright)) {
286N/A _right = new CastExpr(_right, arg1);
286N/A }
286N/A return _type = ptype.resultType();
286N/A }
286N/A throw new TypeCheckError(this);
286N/A }
286N/A
286N/A public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
286N/A if (hasNodeSetArgs() || hasReferenceArgs()) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A
286N/A // Call compare() from the BasisLibrary
286N/A _left.translate(classGen, methodGen);
286N/A _left.startIterator(classGen, methodGen);
286N/A _right.translate(classGen, methodGen);
286N/A _right.startIterator(classGen, methodGen);
286N/A
286N/A il.append(new PUSH(cpg, _op));
286N/A il.append(methodGen.loadDOM());
286N/A
286N/A int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "compare",
286N/A "("
286N/A + _left.getType().toSignature()
286N/A + _right.getType().toSignature()
286N/A + "I"
286N/A + DOM_INTF_SIG
286N/A + ")Z");
286N/A il.append(new INVOKESTATIC(index));
286N/A }
286N/A else {
286N/A translateDesynthesized(classGen, methodGen);
286N/A synthesize(classGen, methodGen);
286N/A }
286N/A }
286N/A
286N/A public void translateDesynthesized(ClassGenerator classGen,
286N/A MethodGenerator methodGen) {
286N/A if (hasNodeSetArgs() || hasReferenceArgs()) {
286N/A translate(classGen, methodGen);
286N/A desynthesize(classGen, methodGen);
286N/A }
286N/A else {
286N/A BranchInstruction bi = null;
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A
286N/A _left.translate(classGen, methodGen);
286N/A _right.translate(classGen, methodGen);
286N/A
286N/A // TODO: optimize if one of the args is 0
286N/A
286N/A boolean tozero = false;
286N/A Type tleft = _left.getType();
286N/A
286N/A if (tleft instanceof RealType) {
286N/A il.append(tleft.CMP(_op == Operators.LT || _op == Operators.LE));
286N/A tleft = Type.Int;
286N/A tozero = true;
286N/A }
286N/A
286N/A switch (_op) {
286N/A case Operators.LT:
286N/A bi = tleft.GE(tozero);
286N/A break;
286N/A
286N/A case Operators.GT:
286N/A bi = tleft.LE(tozero);
286N/A break;
286N/A
286N/A case Operators.LE:
286N/A bi = tleft.GT(tozero);
286N/A break;
286N/A
286N/A case Operators.GE:
286N/A bi = tleft.LT(tozero);
286N/A break;
286N/A
286N/A default:
286N/A ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_RELAT_OP_ERR,this);
286N/A getParser().reportError(Constants.FATAL, msg);
286N/A }
286N/A
286N/A _falseList.add(il.append(bi)); // must be backpatched
286N/A }
286N/A }
286N/A
286N/A public String toString() {
286N/A return Operators.getOpNames(_op) + '(' + _left + ", " + _right + ')';
286N/A }
286N/A}