001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.transformer.bytecode.op;
020
021import lucee.runtime.exp.TemplateException;
022import lucee.transformer.bytecode.BytecodeContext;
023import lucee.transformer.bytecode.BytecodeException;
024import lucee.transformer.bytecode.Literal;
025import lucee.transformer.bytecode.cast.CastBoolean;
026import lucee.transformer.bytecode.expression.ExprBoolean;
027import lucee.transformer.bytecode.expression.Expression;
028import lucee.transformer.bytecode.expression.ExpressionBase;
029import lucee.transformer.bytecode.literal.LitBoolean;
030import lucee.transformer.bytecode.util.Methods;
031import lucee.transformer.bytecode.util.Methods_Operator;
032import lucee.transformer.bytecode.util.Types;
033
034import org.objectweb.asm.Label;
035import org.objectweb.asm.Opcodes;
036import org.objectweb.asm.Type;
037import org.objectweb.asm.commons.GeneratorAdapter;
038
039public final class OpBool extends ExpressionBase implements ExprBoolean {
040
041    public static final int AND=0;
042    public static final int OR=1;
043    public static final int XOR=2;
044        public static final int EQV = 3;
045        public static final int IMP = 4;
046    
047    private ExprBoolean left;
048    private ExprBoolean right;
049    private int operation;
050
051    /**
052     *
053     * @see lucee.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
054     */
055    public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
056        GeneratorAdapter adapter = bc.getAdapter();
057        
058        if(mode==MODE_REF) {
059            _writeOut(bc,MODE_VALUE);
060            adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_BOOLEAN_FROM_BOOLEAN);
061            return Types.BOOLEAN;
062        }
063        
064        
065        Label doFalse = new Label();
066        Label end = new Label();
067
068        if(operation==AND) {
069                left.writeOut(bc, MODE_VALUE);
070                adapter.ifZCmp(Opcodes.IFEQ, doFalse);
071                
072                right.writeOut(bc, MODE_VALUE);
073                adapter.ifZCmp(Opcodes.IFEQ, doFalse);
074                adapter.push(true);
075                
076                adapter.visitJumpInsn(Opcodes.GOTO, end);
077                adapter.visitLabel(doFalse);
078
079                adapter.push(false);
080                adapter.visitLabel(end);
081        }
082        if(operation==OR) {
083                left.writeOut(bc, MODE_VALUE);
084                adapter.ifZCmp(Opcodes.IFNE, doFalse);
085
086                right.writeOut(bc, MODE_VALUE);
087                adapter.ifZCmp(Opcodes.IFNE, doFalse);
088
089                adapter.push(false);
090                adapter.visitJumpInsn(Opcodes.GOTO, end);
091                adapter.visitLabel(doFalse);
092
093                adapter.push(true);
094                adapter.visitLabel(end);
095        }
096        else if(operation==XOR) {
097                left.writeOut(bc, MODE_VALUE);
098                right.writeOut(bc, MODE_VALUE);
099                adapter.visitInsn(Opcodes.IXOR);
100        }
101        else if(operation==EQV) {
102
103            left.writeOut(bc,MODE_VALUE);
104            right.writeOut(bc,MODE_VALUE);
105            adapter.invokeStatic(Types.OPERATOR,Methods_Operator.OPERATOR_EQV_BV_BV);
106        }
107        else if(operation==IMP) {
108
109            left.writeOut(bc,MODE_VALUE);
110            right.writeOut(bc,MODE_VALUE);
111            adapter.invokeStatic(Types.OPERATOR,Methods_Operator.OPERATOR_IMP_BV_BV);
112        }
113        return Types.BOOLEAN_VALUE;
114        
115    }
116    
117
118    
119    
120    
121    
122    
123    private OpBool(Expression left, Expression right, int operation) {
124        super(left.getStart(),right.getEnd());
125        this.left=CastBoolean.toExprBoolean(left);
126        this.right=CastBoolean.toExprBoolean(right);  
127        this.operation=operation;
128    }
129    
130    /**
131     * Create a String expression from a Expression
132     * @param left 
133     * @param right 
134     * 
135     * @return String expression
136     * @throws TemplateException 
137     */
138    public static ExprBoolean toExprBoolean(Expression left, Expression right,int operation) {
139        if(left instanceof Literal && right instanceof Literal) {
140                Boolean l=((Literal) left).getBoolean(null);
141                Boolean r=((Literal) right).getBoolean(null);
142                
143                
144                if(l!=null && r!=null) {
145                        switch(operation) {
146                        case AND:       return new LitBoolean(l.booleanValue()&&r.booleanValue(),left.getStart(),right.getEnd());
147                        case OR:        return new LitBoolean(l.booleanValue()||r.booleanValue(),left.getStart(),right.getEnd());
148                        case XOR:       return new LitBoolean(l.booleanValue()^r.booleanValue(),left.getStart(),right.getEnd());
149                        }
150                }
151        }
152        return new OpBool(left,right,operation);
153    }
154    
155    public String toString(){
156        return left+" "+toStringOperation()+" "+right;
157    }
158
159        private String toStringOperation() {
160                if(AND==operation)      return "and";
161                if(OR==operation)       return "or";
162                if(XOR==operation)      return "xor";
163                if(EQV==operation)      return "eqv";
164                if(IMP==operation)      return "imp";
165                return operation+"";
166        }
167}
168