001    package railo.transformer.bytecode.op;
002    
003    import org.objectweb.asm.Type;
004    import org.objectweb.asm.commons.GeneratorAdapter;
005    import org.objectweb.asm.commons.Method;
006    
007    import railo.runtime.exp.TemplateException;
008    import railo.runtime.op.Caster;
009    import railo.runtime.op.Operator;
010    import railo.transformer.bytecode.BytecodeContext;
011    import railo.transformer.bytecode.BytecodeException;
012    import railo.transformer.bytecode.Literal;
013    import railo.transformer.bytecode.Position;
014    import railo.transformer.bytecode.expression.ExprDouble;
015    import railo.transformer.bytecode.expression.Expression;
016    import railo.transformer.bytecode.expression.ExpressionBase;
017    import railo.transformer.bytecode.literal.LitDouble;
018    import railo.transformer.bytecode.util.Methods;
019    import railo.transformer.bytecode.util.Types;
020    
021    public final class OpDouble extends ExpressionBase implements ExprDouble {
022    
023    
024            private static final Method DIV_REF=new Method("divRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
025            private static final Method INTDIV_REF=new Method("intdivRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
026            private static final Method EXP_REF=new Method("exponentRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
027    
028            private static final Method PLUS_REF=new Method("plusRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
029            private static final Method MINUS_REF=new Method("minusRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
030            private static final Method MODULUS_REF=new Method("modulusRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
031            private static final Method DIVIDE_REF=new Method("divideRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
032            private static final Method MULTIPLY_REF=new Method("multiplyRef",Types.DOUBLE,new Type[]{Types.OBJECT,Types.OBJECT});
033            
034            public static final int PLUS=GeneratorAdapter.ADD;
035        public static final int MINUS=GeneratorAdapter.SUB;
036        public static final int MODULUS=GeneratorAdapter.REM;
037        public static final int DIVIDE=GeneratorAdapter.DIV;
038        public static final int MULTIPLY=GeneratorAdapter.MUL;
039            public static final int EXP = 2000;
040            public static final int INTDIV = 2001;
041            
042        private int operation;
043            private Expression left;
044            private Expression right;
045    
046    
047        
048        // TODO weitere operatoren
049        
050        private OpDouble(Expression left, Expression right, int operation)  {
051            super(left.getStart(),right.getEnd());
052            this.left=      left;
053            this.right=     right;   
054            this.operation=operation;
055        }
056        
057        /**
058         * Create a String expression from a Expression
059         * @param left 
060         * @param right 
061         * @param operation 
062         * 
063         * @return String expression
064         * @throws TemplateException 
065         */
066        public static ExprDouble toExprDouble(Expression left, Expression right,int operation)  {
067            
068            if(left instanceof Literal && right instanceof Literal) {
069                    Double l = ((Literal)left).getDouble(null);
070                Double r = ((Literal)right).getDouble(null);
071                    
072                if(l!=null && r !=null) {
073                    switch(operation) {
074                    case PLUS: return toLitDouble(          l.doubleValue()+r.doubleValue(),left.getStart(),right.getEnd());
075                    case MINUS: return toLitDouble(         l.doubleValue()-r.doubleValue(),left.getStart(),right.getEnd());
076                    case MODULUS: return toLitDouble(       l.doubleValue()%r.doubleValue(),left.getStart(),right.getEnd());
077                    case DIVIDE: {
078                            if(r.doubleValue()!=0d)
079                                    return toLitDouble(     l.doubleValue()/r.doubleValue(),left.getStart(),right.getEnd());
080                            break;
081                    }
082                    case MULTIPLY: return toLitDouble(      l.doubleValue()*r.doubleValue(),left.getStart(),right.getEnd());
083                    case EXP: return LitDouble.toExprDouble(Operator.exponent(l.doubleValue(),r.doubleValue()),left.getStart(),right.getEnd());
084                    case INTDIV: return LitDouble.toExprDouble(l.intValue()/r.intValue(),left.getStart(),right.getEnd());
085                    
086                    }
087                }
088            }
089            return new OpDouble(left,right,operation);
090        }
091        
092        
093        private static ExprDouble toLitDouble(double d, Position start, Position end) {
094            return LitDouble.toExprDouble(Caster.toDoubleValue(Caster.toString(d),0),start,end);
095            }
096    
097            /**
098         *
099         * @see railo.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
100         */
101        public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
102            return writeOutDouble(bc, mode) ;
103        }
104        
105        public Type writeOutDouble(BytecodeContext bc, int mode) throws BytecodeException {
106            GeneratorAdapter adapter = bc.getAdapter();
107            
108            left.writeOut(bc,MODE_REF);
109            right.writeOut(bc,MODE_REF);
110            
111            
112            if(operation==EXP) {
113                    adapter.invokeStatic(Types.OPERATOR,EXP_REF);
114            }
115            else if(operation==DIVIDE) {
116                    adapter.invokeStatic(Types.OPERATOR,DIV_REF);
117            }
118            else if(operation==INTDIV) {
119                    adapter.invokeStatic(Types.OPERATOR,INTDIV_REF);
120            }
121            else if(operation==PLUS) {
122                    adapter.invokeStatic(Types.OPERATOR,PLUS_REF);
123            }
124            else if(operation==MINUS) {
125                    adapter.invokeStatic(Types.OPERATOR,MINUS_REF);
126            }
127            else if(operation==MODULUS) {
128                    adapter.invokeStatic(Types.OPERATOR,MODULUS_REF);
129            }
130            else if(operation==DIVIDE) {
131                    adapter.invokeStatic(Types.OPERATOR,DIVIDE_REF);
132            }
133            else if(operation==MULTIPLY) {
134                    adapter.invokeStatic(Types.OPERATOR,MULTIPLY_REF);
135            }
136            
137    
138            if(mode==MODE_VALUE) {
139                adapter.invokeStatic(Types.CASTER,Methods.METHOD_TO_DOUBLE_VALUE_FROM_DOUBLE);
140                return Types.DOUBLE_VALUE;
141            }
142            
143            
144            
145            return Types.DOUBLE;
146        }
147    
148    }