| /* |
| * @(#)$Id$ |
| * |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2001-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 2001, Sun |
| * Microsystems., http://www.sun.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| * |
| * @author Jacek Ambroziak |
| * @author Santiago Pericas-Geertsen |
| * @author Morten Jorgensen |
| * |
| */ |
| |
| package org.apache.xalan.xsltc.compiler; |
| |
| import org.apache.bcel.generic.GOTO; |
| import org.apache.bcel.generic.InstructionHandle; |
| import org.apache.bcel.generic.InstructionList; |
| import org.apache.xalan.xsltc.compiler.util.ClassGenerator; |
| import org.apache.xalan.xsltc.compiler.util.MethodGenerator; |
| import org.apache.xalan.xsltc.compiler.util.MethodType; |
| import org.apache.xalan.xsltc.compiler.util.Type; |
| import org.apache.xalan.xsltc.compiler.util.TypeCheckError; |
| |
| final class LogicalExpr extends Expression { |
| |
| public static final int OR = 0; |
| public static final int AND = 1; |
| |
| private final int _op; // operator |
| private Expression _left; // first operand |
| private Expression _right; // second operand |
| |
| private static final String[] Ops = { "or", "and" }; |
| |
| /** |
| * Creates a new logical expression - either OR or AND. Note that the |
| * left- and right-hand side expressions can also be logical expressions, |
| * thus creating logical trees representing structures such as |
| * (a and (b or c) and d), etc... |
| */ |
| public LogicalExpr(int op, Expression left, Expression right) { |
| _op = op; |
| (_left = left).setParent(this); |
| (_right = right).setParent(this); |
| } |
| |
| /** |
| * Returns true if this expressions contains a call to position(). This is |
| * needed for context changes in node steps containing multiple predicates. |
| */ |
| public boolean hasPositionCall() { |
| return (_left.hasPositionCall() || _right.hasPositionCall()); |
| } |
| |
| /** |
| * Returns true if this expressions contains a call to last() |
| */ |
| public boolean hasLastCall() { |
| return (_left.hasLastCall() || _right.hasLastCall()); |
| } |
| |
| /** |
| * Returns an object representing the compile-time evaluation |
| * of an expression. We are only using this for function-available |
| * and element-available at this time. |
| */ |
| public Object evaluateAtCompileTime() { |
| final Object leftb = _left.evaluateAtCompileTime(); |
| final Object rightb = _right.evaluateAtCompileTime(); |
| |
| // Return null if we can't evaluate at compile time |
| if (leftb == null || rightb == null) { |
| return null; |
| } |
| |
| if (_op == AND) { |
| return (leftb == Boolean.TRUE && rightb == Boolean.TRUE) ? |
| Boolean.TRUE : Boolean.FALSE; |
| } |
| else { |
| return (leftb == Boolean.TRUE || rightb == Boolean.TRUE) ? |
| Boolean.TRUE : Boolean.FALSE; |
| } |
| } |
| |
| /** |
| * Returns this logical expression's operator - OR or AND represented |
| * by 0 and 1 respectively. |
| */ |
| public int getOp() { |
| return(_op); |
| } |
| |
| /** |
| * Override the SyntaxTreeNode.setParser() method to make sure that the |
| * parser is set for sub-expressions |
| */ |
| public void setParser(Parser parser) { |
| super.setParser(parser); |
| _left.setParser(parser); |
| _right.setParser(parser); |
| } |
| |
| /** |
| * Returns a string describing this expression |
| */ |
| public String toString() { |
| return Ops[_op] + '(' + _left + ", " + _right + ')'; |
| } |
| |
| /** |
| * Type-check this expression, and possibly child expressions. |
| */ |
| public Type typeCheck(SymbolTable stable) throws TypeCheckError { |
| // Get the left and right operand types |
| Type tleft = _left.typeCheck(stable); |
| Type tright = _right.typeCheck(stable); |
| |
| // Check if the operator supports the two operand types |
| MethodType wantType = new MethodType(Type.Void, tleft, tright); |
| MethodType haveType = lookupPrimop(stable, Ops[_op], wantType); |
| |
| // Yes, the operation is supported |
| if (haveType != null) { |
| // Check if left-hand side operand must be type casted |
| Type arg1 = (Type)haveType.argsType().elementAt(0); |
| if (!arg1.identicalTo(tleft)) |
| _left = new CastExpr(_left, arg1); |
| // Check if right-hand side operand must be type casted |
| Type arg2 = (Type) haveType.argsType().elementAt(1); |
| if (!arg2.identicalTo(tright)) |
| _right = new CastExpr(_right, arg1); |
| // Return the result type for the operator we will use |
| return _type = haveType.resultType(); |
| } |
| throw new TypeCheckError(this); |
| } |
| |
| /** |
| * Compile the expression - leave boolean expression on stack |
| */ |
| public void translate(ClassGenerator classGen, MethodGenerator methodGen) { |
| translateDesynthesized(classGen, methodGen); |
| synthesize(classGen, methodGen); |
| } |
| |
| /** |
| * Compile expression and update true/false-lists |
| */ |
| public void translateDesynthesized(ClassGenerator classGen, |
| MethodGenerator methodGen) { |
| |
| final InstructionList il = methodGen.getInstructionList(); |
| final SyntaxTreeNode parent = getParent(); |
| |
| // Compile AND-expression |
| if (_op == AND) { |
| |
| // Translate left hand side - must be true |
| _left.translateDesynthesized(classGen, methodGen); |
| |
| // Need this for chaining any OR-expression children |
| InstructionHandle middle = il.append(NOP); |
| |
| // Translate left right side - must be true |
| _right.translateDesynthesized(classGen, methodGen); |
| |
| // Need this for chaining any OR-expression children |
| InstructionHandle after = il.append(NOP); |
| |
| // Append child expression false-lists to our false-list |
| _falseList.append(_right._falseList.append(_left._falseList)); |
| |
| // Special case for OR-expression as a left child of AND. |
| // The true-list of OR must point to second clause of AND. |
| if ((_left instanceof LogicalExpr) && |
| (((LogicalExpr)_left).getOp() == OR)) { |
| _left.backPatchTrueList(middle); |
| } |
| else if (_left instanceof NotCall) { |
| _left.backPatchTrueList(middle); |
| } |
| else { |
| _trueList.append(_left._trueList); |
| } |
| |
| // Special case for OR-expression as a right child of AND |
| // The true-list of OR must point to true-list of AND. |
| if ((_right instanceof LogicalExpr) && |
| (((LogicalExpr)_right).getOp() == OR)) { |
| _right.backPatchTrueList(after); |
| } |
| else if (_right instanceof NotCall) { |
| _right.backPatchTrueList(after); |
| } |
| else { |
| _trueList.append(_right._trueList); |
| } |
| } |
| // Compile OR-expression |
| else { |
| // Translate left-hand side expression and produce true/false list |
| _left.translateDesynthesized(classGen, methodGen); |
| |
| // This GOTO is used to skip over the code for the last test |
| // in the case where the the first test succeeds |
| InstructionHandle ih = il.append(new GOTO(null)); |
| |
| // Translate right-hand side expression and produce true/false list |
| _right.translateDesynthesized(classGen, methodGen); |
| |
| _left._trueList.backPatch(ih); |
| _left._falseList.backPatch(ih.getNext()); |
| |
| _falseList.append(_right._falseList); |
| _trueList.add(ih).append(_right._trueList); |
| } |
| } |
| } |