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