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: LogicalExpr.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.GOTO; 025 import org.apache.bcel.generic.InstructionHandle; 026 import org.apache.bcel.generic.InstructionList; 027 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 028 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 029 import org.apache.xalan.xsltc.compiler.util.MethodType; 030 import org.apache.xalan.xsltc.compiler.util.Type; 031 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 032 033 /** 034 * @author Jacek Ambroziak 035 * @author Santiago Pericas-Geertsen 036 * @author Morten Jorgensen 037 */ 038 final class LogicalExpr extends Expression { 039 040 public static final int OR = 0; 041 public static final int AND = 1; 042 043 private final int _op; // operator 044 private Expression _left; // first operand 045 private Expression _right; // second operand 046 047 private static final String[] Ops = { "or", "and" }; 048 049 /** 050 * Creates a new logical expression - either OR or AND. Note that the 051 * left- and right-hand side expressions can also be logical expressions, 052 * thus creating logical trees representing structures such as 053 * (a and (b or c) and d), etc... 054 */ 055 public LogicalExpr(int op, Expression left, Expression right) { 056 _op = op; 057 (_left = left).setParent(this); 058 (_right = right).setParent(this); 059 } 060 061 /** 062 * Returns true if this expressions contains a call to position(). This is 063 * needed for context changes in node steps containing multiple predicates. 064 */ 065 public boolean hasPositionCall() { 066 return (_left.hasPositionCall() || _right.hasPositionCall()); 067 } 068 069 /** 070 * Returns true if this expressions contains a call to last() 071 */ 072 public boolean hasLastCall() { 073 return (_left.hasLastCall() || _right.hasLastCall()); 074 } 075 076 /** 077 * Returns an object representing the compile-time evaluation 078 * of an expression. We are only using this for function-available 079 * and element-available at this time. 080 */ 081 public Object evaluateAtCompileTime() { 082 final Object leftb = _left.evaluateAtCompileTime(); 083 final Object rightb = _right.evaluateAtCompileTime(); 084 085 // Return null if we can't evaluate at compile time 086 if (leftb == null || rightb == null) { 087 return null; 088 } 089 090 if (_op == AND) { 091 return (leftb == Boolean.TRUE && rightb == Boolean.TRUE) ? 092 Boolean.TRUE : Boolean.FALSE; 093 } 094 else { 095 return (leftb == Boolean.TRUE || rightb == Boolean.TRUE) ? 096 Boolean.TRUE : Boolean.FALSE; 097 } 098 } 099 100 /** 101 * Returns this logical expression's operator - OR or AND represented 102 * by 0 and 1 respectively. 103 */ 104 public int getOp() { 105 return(_op); 106 } 107 108 /** 109 * Override the SyntaxTreeNode.setParser() method to make sure that the 110 * parser is set for sub-expressions 111 */ 112 public void setParser(Parser parser) { 113 super.setParser(parser); 114 _left.setParser(parser); 115 _right.setParser(parser); 116 } 117 118 /** 119 * Returns a string describing this expression 120 */ 121 public String toString() { 122 return Ops[_op] + '(' + _left + ", " + _right + ')'; 123 } 124 125 /** 126 * Type-check this expression, and possibly child expressions. 127 */ 128 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 129 // Get the left and right operand types 130 Type tleft = _left.typeCheck(stable); 131 Type tright = _right.typeCheck(stable); 132 133 // Check if the operator supports the two operand types 134 MethodType wantType = new MethodType(Type.Void, tleft, tright); 135 MethodType haveType = lookupPrimop(stable, Ops[_op], wantType); 136 137 // Yes, the operation is supported 138 if (haveType != null) { 139 // Check if left-hand side operand must be type casted 140 Type arg1 = (Type)haveType.argsType().elementAt(0); 141 if (!arg1.identicalTo(tleft)) 142 _left = new CastExpr(_left, arg1); 143 // Check if right-hand side operand must be type casted 144 Type arg2 = (Type) haveType.argsType().elementAt(1); 145 if (!arg2.identicalTo(tright)) 146 _right = new CastExpr(_right, arg1); 147 // Return the result type for the operator we will use 148 return _type = haveType.resultType(); 149 } 150 throw new TypeCheckError(this); 151 } 152 153 /** 154 * Compile the expression - leave boolean expression on stack 155 */ 156 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 157 translateDesynthesized(classGen, methodGen); 158 synthesize(classGen, methodGen); 159 } 160 161 /** 162 * Compile expression and update true/false-lists 163 */ 164 public void translateDesynthesized(ClassGenerator classGen, 165 MethodGenerator methodGen) { 166 167 final InstructionList il = methodGen.getInstructionList(); 168 final SyntaxTreeNode parent = getParent(); 169 170 // Compile AND-expression 171 if (_op == AND) { 172 173 // Translate left hand side - must be true 174 _left.translateDesynthesized(classGen, methodGen); 175 176 // Need this for chaining any OR-expression children 177 InstructionHandle middle = il.append(NOP); 178 179 // Translate left right side - must be true 180 _right.translateDesynthesized(classGen, methodGen); 181 182 // Need this for chaining any OR-expression children 183 InstructionHandle after = il.append(NOP); 184 185 // Append child expression false-lists to our false-list 186 _falseList.append(_right._falseList.append(_left._falseList)); 187 188 // Special case for OR-expression as a left child of AND. 189 // The true-list of OR must point to second clause of AND. 190 if ((_left instanceof LogicalExpr) && 191 (((LogicalExpr)_left).getOp() == OR)) { 192 _left.backPatchTrueList(middle); 193 } 194 else if (_left instanceof NotCall) { 195 _left.backPatchTrueList(middle); 196 } 197 else { 198 _trueList.append(_left._trueList); 199 } 200 201 // Special case for OR-expression as a right child of AND 202 // The true-list of OR must point to true-list of AND. 203 if ((_right instanceof LogicalExpr) && 204 (((LogicalExpr)_right).getOp() == OR)) { 205 _right.backPatchTrueList(after); 206 } 207 else if (_right instanceof NotCall) { 208 _right.backPatchTrueList(after); 209 } 210 else { 211 _trueList.append(_right._trueList); 212 } 213 } 214 // Compile OR-expression 215 else { 216 // Translate left-hand side expression and produce true/false list 217 _left.translateDesynthesized(classGen, methodGen); 218 219 // This GOTO is used to skip over the code for the last test 220 // in the case where the the first test succeeds 221 InstructionHandle ih = il.append(new GOTO(null)); 222 223 // Translate right-hand side expression and produce true/false list 224 _right.translateDesynthesized(classGen, methodGen); 225 226 _left._trueList.backPatch(ih); 227 _left._falseList.backPatch(ih.getNext()); 228 229 _falseList.append(_right._falseList); 230 _trueList.add(ih).append(_right._trueList); 231 } 232 } 233 }