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.expression.var;
020
021import lucee.runtime.type.FunctionValueImpl;
022import lucee.transformer.bytecode.BytecodeContext;
023import lucee.transformer.bytecode.BytecodeException;
024import lucee.transformer.bytecode.cast.CastString;
025import lucee.transformer.bytecode.expression.Expression;
026import lucee.transformer.bytecode.literal.LitString;
027import lucee.transformer.bytecode.literal.Null;
028import lucee.transformer.bytecode.util.Types;
029import lucee.transformer.bytecode.visitor.ArrayVisitor;
030
031import org.objectweb.asm.Type;
032import org.objectweb.asm.commons.GeneratorAdapter;
033import org.objectweb.asm.commons.Method;
034
035public final class NamedArgument extends Argument {
036        
037
038
039        private static final Type TYPE_FUNCTION_VALUE=Type.getType(FunctionValueImpl.class);
040    private static final int VALUE=0;
041    private static final int ARRAY=1;
042    private static final int KEY=0;
043    private static final int STRING=1;
044    
045    private final static Method[][]  NEW_INSTANCE = new Method[][]{
046        new Method[]{
047                        new Method("newInstance",Types.FUNCTION_VALUE,new Type[]{Types.COLLECTION_KEY,Types.OBJECT}),
048                        new Method("newInstance",Types.FUNCTION_VALUE,new Type[]{Types.COLLECTION_KEY_ARRAY,Types.OBJECT})
049        },
050        new Method[]{
051                        new Method("newInstance",Types.FUNCTION_VALUE,new Type[]{Types.STRING,Types.OBJECT}),
052                        new Method("newInstance",Types.FUNCTION_VALUE,new Type[]{Types.STRING_ARRAY,Types.OBJECT})
053        }
054    };
055        
056    
057    private Expression name;
058        private boolean varKeyUpperCase;
059
060        public NamedArgument(Expression name, Expression value, String type, boolean varKeyUpperCase) {
061                super(value,type);
062                this.name=name instanceof Null?LitString.toExprString(varKeyUpperCase?"NULL":"null"):name;
063                this.varKeyUpperCase=varKeyUpperCase;
064        }
065
066        @Override
067        public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
068                
069                int form=VALUE;
070                int type=STRING;
071                if(name instanceof Variable && !((Variable)name).fromHash()) {
072                        GeneratorAdapter adapter = bc.getAdapter();
073                        String[] arr = VariableString.variableToStringArray((Variable) name,true);
074                        if(arr.length>1){
075                                form=ARRAY;
076                                ArrayVisitor av=new ArrayVisitor();
077                    av.visitBegin(adapter,Types.STRING,arr.length);
078                    for(int y=0;y<arr.length;y++){
079                                av.visitBeginItem(adapter, y);
080                                        adapter.push(varKeyUpperCase?arr[y].toUpperCase():arr[y]);
081                                av.visitEndItem(bc.getAdapter());
082                    }
083                    av.visitEnd();
084                        }
085                        else {
086                                //VariableString.toExprString(name).writeOut(bc, MODE_REF);
087                                String str = VariableString.variableToString((Variable) name,true);
088                                name=LitString.toExprString(varKeyUpperCase?str.toUpperCase():str);
089                                Variable.registerKey(bc, VariableString.toExprString(name));
090                                type=KEY;
091                        }
092                }
093                else  {
094                        //CastString.toExprString(name).writeOut(bc, MODE_REF);
095                        Variable.registerKey(bc, CastString.toExprString(name));
096                        type=KEY;
097                        
098                }
099                //name.writeOut(bc, MODE_REF);
100                super._writeOut(bc, MODE_REF);
101                //bc.getAdapter().push(variableString);
102                bc.getAdapter().invokeStatic(TYPE_FUNCTION_VALUE,NEW_INSTANCE[type][form]);
103                return Types.FUNCTION_VALUE;
104        }
105
106        
107        @Override
108        public Type writeOutValue(BytecodeContext bc, int mode) throws BytecodeException {
109                return super.writeOutValue(bc, mode);
110        }
111
112
113    /**
114         * @return the name
115         */
116        public Expression getName() {
117                return name;
118        }
119}