1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Nov 2017 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.GOTO; 25 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 26 import com.sun.org.apache.bcel.internal.generic.InstructionList; 27 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 32 33 /** 34 * @author Jacek Ambroziak 35 * @author Santiago Pericas-Geertsen 36 * @author Morten Jorgensen 37 */ 38 final class LogicalExpr extends Expression { 39 40 public static final int OR = 0; 41 public static final int AND = 1; 42 43 private final int _op; // operator 44 private Expression _left; // first operand 45 private Expression _right; // second operand 46 47 private static final String[] Ops = { "or", "and" }; 48 49 /** 50 * Creates a new logical expression - either OR or AND. Note that the 51 * left- and right-hand side expressions can also be logical expressions, 52 * thus creating logical trees representing structures such as 53 * (a and (b or c) and d), etc... 54 */ 55 public LogicalExpr(int op, Expression left, Expression right) { 56 _op = op; 57 (_left = left).setParent(this); 58 (_right = right).setParent(this); 59 } 60 61 /** 62 * Returns true if this expressions contains a call to position(). This is 63 * needed for context changes in node steps containing multiple predicates. 64 */ 65 public boolean hasPositionCall() { 66 return (_left.hasPositionCall() || _right.hasPositionCall()); 67 } 68 69 /** 70 * Returns true if this expressions contains a call to last() 71 */ 72 public boolean hasLastCall() { 73 return (_left.hasLastCall() || _right.hasLastCall()); 74 } 75 76 /** 77 * Returns an object representing the compile-time evaluation 78 * of an expression. We are only using this for function-available 79 * and element-available at this time. 80 */ 81 public Object evaluateAtCompileTime() { 82 final Object leftb = _left.evaluateAtCompileTime(); 83 final Object rightb = _right.evaluateAtCompileTime(); 84 85 // Return null if we can't evaluate at compile time 86 if (leftb == null || rightb == null) { 87 return null; 88 } 89 90 if (_op == AND) { 91 return (leftb == Boolean.TRUE && rightb == Boolean.TRUE) ? 92 Boolean.TRUE : Boolean.FALSE; 93 } 94 else { 95 return (leftb == Boolean.TRUE || rightb == Boolean.TRUE) ? 96 Boolean.TRUE : Boolean.FALSE; 97 } 98 } 99 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 = haveType.argsType().get(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 = haveType.argsType().get(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 }