001    package railo.transformer.bytecode.op;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    import org.objectweb.asm.Label;
008    import org.objectweb.asm.Opcodes;
009    import org.objectweb.asm.Type;
010    import org.objectweb.asm.commons.GeneratorAdapter;
011    import org.objectweb.asm.commons.Method;
012    
013    import railo.runtime.op.Elvis;
014    import railo.transformer.bytecode.BytecodeContext;
015    import railo.transformer.bytecode.BytecodeException;
016    import railo.transformer.bytecode.Literal;
017    import railo.transformer.bytecode.expression.Expression;
018    import railo.transformer.bytecode.expression.ExpressionBase;
019    import railo.transformer.bytecode.expression.var.DataMember;
020    import railo.transformer.bytecode.expression.var.Member;
021    import railo.transformer.bytecode.expression.var.Variable;
022    import railo.transformer.bytecode.util.ExpressionUtil;
023    import railo.transformer.bytecode.util.Types;
024    import railo.transformer.bytecode.visitor.ArrayVisitor;
025    
026    public final class OpElvis extends ExpressionBase {
027    
028            
029    
030        private static final Type ELVIS=Type.getType(Elvis.class);
031        public static final Method INVOKE_STR = new Method(
032                    "operate",
033                    Types.BOOLEAN_VALUE,
034                    new Type[]{Types.PAGE_CONTEXT,Types.DOUBLE_VALUE,Types.STRING_ARRAY});
035            
036        public static final Method INVOKE_KEY = new Method(
037                    "operate",
038                    Types.BOOLEAN_VALUE,
039                    new Type[]{Types.PAGE_CONTEXT,Types.DOUBLE_VALUE,Types.COLLECTION_KEY_ARRAY});
040            
041            private Variable left;
042        private Expression right;
043    
044        /**
045         *
046         * @see railo.transformer.bytecode.expression.ExpressionBase#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int)
047         */
048        public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
049            GeneratorAdapter adapter = bc.getAdapter();
050            
051            Label yes = new Label();
052            Label end = new Label();
053            
054            List<Member> members = left.getMembers();
055            Iterator<Member> it = members.iterator();
056            
057            // to array
058            List<DataMember> list=new ArrayList<DataMember>();
059            while(it.hasNext()){
060                    list.add((DataMember) it.next());
061            }
062            DataMember[] arr = list.toArray(new DataMember[members.size()]);
063            
064            ExpressionUtil.visitLine(bc, left.getStart());
065            
066        // public static boolean call(PageContext pc , double scope,String[] varNames)
067            // pc
068            adapter.loadArg(0);
069            // scope
070                    adapter.push((double)left.getScope());
071                    //varNames
072                    
073                    // all literal string?
074                    boolean allLiteral=true;
075                    for(int i=0;i<arr.length;i++){
076                            if(!(arr[i].getName() instanceof Literal)) allLiteral=false;
077                    }
078                    
079                    ArrayVisitor av=new ArrayVisitor();
080                    if(!allLiteral) {
081                            // String Array
082                    av.visitBegin(adapter,Types.STRING,arr.length);
083                    for(int i=0;i<arr.length;i++){
084                                    av.visitBeginItem(adapter, i);
085                                            arr[i].getName().writeOut(bc, MODE_REF); 
086                                    av.visitEndItem(adapter);
087                    }
088                    }
089                    else {
090                            // Collection.Key Array
091                    av.visitBegin(adapter,Types.COLLECTION_KEY,arr.length);
092                    for(int i=0;i<arr.length;i++){
093                                    av.visitBeginItem(adapter, i);
094                                            Variable.registerKey(bc, arr[i].getName());
095                                    av.visitEndItem(adapter);
096                    }
097                    }
098            av.visitEnd();
099                    
100            
101            // allowNull
102            //adapter.push(false);
103                    
104            
105            
106                    //ASMConstants.NULL(adapter);
107                    
108            // call IsDefined.invoke
109            adapter.invokeStatic(ELVIS, allLiteral?INVOKE_KEY:INVOKE_STR);
110                    ExpressionUtil.visitLine(bc, left.getEnd());
111            
112            
113            adapter.visitJumpInsn(Opcodes.IFEQ, yes);
114            
115            // left
116            ExpressionUtil.visitLine(bc, left.getStart());
117            left.writeOut(bc, MODE_REF);
118            ExpressionUtil.visitLine(bc, left.getEnd());
119            adapter.visitJumpInsn(Opcodes.GOTO, end);
120            
121            // right
122            ExpressionUtil.visitLine(bc, right.getStart());
123            adapter.visitLabel(yes);
124            right.writeOut(bc, MODE_REF);
125            ExpressionUtil.visitLine(bc, right.getEnd());
126            adapter.visitLabel(end);
127            
128            return Types.OBJECT;
129            
130        }
131        
132    
133        
134        
135        
136        
137        
138        private OpElvis(Variable left, Expression right) {
139            super(left.getStart(),right.getEnd());
140            this.left=left;
141            this.right=right;  
142        }
143        
144    
145        public static Expression toExpr(Variable left, Expression right) {
146            return new OpElvis(left,right);
147        }
148    }
149