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 java.math.BigDecimal;
022
023import lucee.transformer.bytecode.BytecodeContext;
024import lucee.transformer.bytecode.BytecodeException;
025import lucee.transformer.bytecode.expression.Expression;
026import lucee.transformer.bytecode.expression.ExpressionBase;
027import lucee.transformer.bytecode.util.Types;
028
029import org.objectweb.asm.Type;
030import org.objectweb.asm.commons.GeneratorAdapter;
031import org.objectweb.asm.commons.Method;
032
033public final class OpBigDecimal extends ExpressionBase {
034
035        private static final Method TO_BIG_DECIMAL = new Method("toBigDecimal",Types.BIG_DECIMAL,new Type[]{Types.OBJECT});
036        
037        private static final Method _ADD = new Method("add",Types.BIG_DECIMAL,new Type[]{Types.BIG_DECIMAL});
038        private static final Method _SUBSTRACT = new Method("subtract",Types.BIG_DECIMAL,new Type[]{Types.BIG_DECIMAL});
039        private static final Method _DIVIDE= new Method("divide",Types.BIG_DECIMAL,new Type[]{Types.BIG_DECIMAL,Types.INT_VALUE,Types.INT_VALUE});
040        private static final Method _MULTIPLY= new Method("multiply",Types.BIG_DECIMAL,new Type[]{Types.BIG_DECIMAL});
041        private static final Method _REMAINER= new Method("remainder",Types.BIG_DECIMAL,new Type[]{Types.BIG_DECIMAL});
042        
043    private int operation;
044        private Expression left;
045        private Expression right;
046
047    public OpBigDecimal(Expression left, Expression right, int operation)  {
048        super(left.getStart(),right.getEnd());
049        this.left=      left;
050        this.right=     right;   
051        this.operation=operation;
052    }
053    
054
055        /**
056     *
057     * @see lucee.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
058     */
059    public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
060        return writeOutDouble(bc, mode) ;
061    }
062    
063    public Type writeOutDouble(BytecodeContext bc, int mode) throws BytecodeException {
064
065        if(operation==OpDouble.EXP) {
066                return new OpDouble(left, right, operation).writeOutDouble(bc, mode);
067        }
068        
069        GeneratorAdapter adapter = bc.getAdapter();
070        
071        
072        toBigDecimal(bc,left);
073        toBigDecimal(bc,right);
074        
075        
076        //Caster.toBigDecimal("1").add(Caster.toBigDecimal("1"));
077        if(operation==OpDouble.PLUS) {
078                adapter.invokeVirtual(Types.BIG_DECIMAL, _ADD);
079        }
080        else if(operation==OpDouble.MINUS) {
081                adapter.invokeVirtual(Types.BIG_DECIMAL, _SUBSTRACT);
082        }
083        else if(operation==OpDouble.DIVIDE) {
084                adapter.push(34);
085                adapter.push( BigDecimal.ROUND_HALF_EVEN);
086                adapter.invokeVirtual(Types.BIG_DECIMAL, _DIVIDE);
087        }
088        else if(operation==OpDouble.INTDIV) {
089                adapter.push(0);
090                adapter.push( BigDecimal.ROUND_DOWN);
091                adapter.invokeVirtual(Types.BIG_DECIMAL, _DIVIDE);
092        }
093        else if(operation==OpDouble.MULTIPLY) {
094                adapter.invokeVirtual(Types.BIG_DECIMAL, _MULTIPLY);
095        }
096        
097        else if(operation==OpDouble.MODULUS) {
098                adapter.invokeVirtual(Types.BIG_DECIMAL, _REMAINER);
099        }
100        return Types.BIG_DECIMAL;
101    }
102    
103
104
105        private static void toBigDecimal(BytecodeContext bc, Expression expr) throws BytecodeException {
106                expr.writeOut(bc,MODE_REF);
107        if(expr instanceof OpBigDecimal) return;
108        bc.getAdapter().invokeStatic(Types.CASTER,TO_BIG_DECIMAL);
109        }
110
111
112        public Expression getLeft() {
113                return left;
114        }
115
116        public Expression getRight() {
117                return right;
118        }
119
120
121}