001    package railo.transformer.bytecode.expression.var;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    import org.objectweb.asm.Opcodes;
008    import org.objectweb.asm.Type;
009    import org.objectweb.asm.commons.GeneratorAdapter;
010    import org.objectweb.asm.commons.Method;
011    
012    import railo.commons.lang.StringUtil;
013    import railo.runtime.exp.TemplateException;
014    import railo.runtime.type.scope.Scope;
015    import railo.runtime.type.scope.ScopeSupport;
016    import railo.runtime.type.util.ArrayUtil;
017    import railo.runtime.type.util.KeyConstants;
018    import railo.runtime.type.util.UDFUtil;
019    import railo.runtime.util.VariableUtilImpl;
020    import railo.transformer.bytecode.BytecodeContext;
021    import railo.transformer.bytecode.BytecodeException;
022    import railo.transformer.bytecode.Literal;
023    import railo.transformer.bytecode.Position;
024    import railo.transformer.bytecode.cast.CastOther;
025    import railo.transformer.bytecode.expression.ExprString;
026    import railo.transformer.bytecode.expression.Expression;
027    import railo.transformer.bytecode.expression.ExpressionBase;
028    import railo.transformer.bytecode.expression.Invoker;
029    import railo.transformer.bytecode.literal.LitBoolean;
030    import railo.transformer.bytecode.literal.LitDouble;
031    import railo.transformer.bytecode.literal.LitString;
032    import railo.transformer.bytecode.util.ASMConstants;
033    import railo.transformer.bytecode.util.ASMUtil;
034    import railo.transformer.bytecode.util.ExpressionUtil;
035    import railo.transformer.bytecode.util.TypeScope;
036    import railo.transformer.bytecode.util.Types;
037    import railo.transformer.library.function.FunctionLibFunction;
038    import railo.transformer.library.function.FunctionLibFunctionArg;
039    
040    public class Variable extends ExpressionBase implements Invoker {
041             
042    
043            private static final Type KEY_CONSTANTS = Type.getType(KeyConstants.class);
044    
045            // java.lang.Object get(java.lang.String)
046            final static Method METHOD_SCOPE_GET_KEY = new Method("get",
047                            Types.OBJECT,
048                            new Type[]{Types.COLLECTION_KEY});
049            // Object getCollection(java.lang.String)
050            final static Method METHOD_SCOPE_GET_COLLECTION_KEY= new Method("getCollection",
051                            Types.OBJECT,
052                            new Type[]{Types.COLLECTION_KEY});
053    
054            // java.lang.Object get(java.lang.String)
055            final static Method METHOD_SCOPE_GET = new Method("get",
056                            Types.OBJECT,
057                            new Type[]{Types.STRING});
058            // Object getCollection(java.lang.String)
059            final static Method METHOD_SCOPE_GET_COLLECTION= new Method("getCollection",
060                            Types.OBJECT,
061                            new Type[]{Types.STRING});
062    
063        final static Method[] METHODS_SCOPE_GET = new Method[6];
064        static {
065                METHODS_SCOPE_GET[0] = METHOD_SCOPE_GET;
066                METHODS_SCOPE_GET[1] = new Method("get",Types.OBJECT,new Type[]{Types.SCOPE,Types.STRING,Types.STRING}); 
067                METHODS_SCOPE_GET[2] = new Method("get",Types.OBJECT,new Type[]{Types.SCOPE,Types.STRING,Types.STRING,Types.STRING});
068                METHODS_SCOPE_GET[3] = new Method("get",Types.OBJECT,new Type[]{Types.SCOPE,Types.STRING,Types.STRING,Types.STRING,Types.STRING});
069                METHODS_SCOPE_GET[4] = new Method("get",Types.OBJECT,new Type[]{Types.SCOPE,Types.STRING,Types.STRING,Types.STRING,Types.STRING,Types.STRING});
070                METHODS_SCOPE_GET[5] = new Method("get",Types.OBJECT,new Type[]{Types.SCOPE,Types.STRING,Types.STRING,Types.STRING,Types.STRING,Types.STRING,Types.STRING});
071        }
072        
073        // Object getCollection (Object,String)
074        private final static Method GET_COLLECTION = new Method("getCollection",
075                            Types.OBJECT,
076                            new Type[]{Types.OBJECT,Types.STRING});
077        // Object get (Object,String)
078        private final static Method GET = new Method("get",
079                            Types.OBJECT,
080                            new Type[]{Types.OBJECT,Types.STRING});
081    
082        
083        // Object getCollection (Object,String)
084        private final static Method GET_COLLECTION_KEY = new Method("getCollection",
085                            Types.OBJECT,
086                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY});
087        // Object get (Object,String)
088        private final static Method GET_KEY = new Method("get",
089                            Types.OBJECT,
090                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY});
091        
092    
093        
094        // Object getFunction (Object,String,Object[])
095        private final static Method GET_FUNCTION = new Method("getFunction",
096                            Types.OBJECT,
097                            new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY});
098        // Object getFunctionWithNamedValues (Object,String,Object[])
099        private final static Method GET_FUNCTION_WITH_NAMED_ARGS = new Method("getFunctionWithNamedValues",
100                            Types.OBJECT,
101                            new Type[]{Types.OBJECT,Types.STRING,Types.OBJECT_ARRAY});
102        
103    
104        // Object getFunction (Object,String,Object[])
105        private final static Method GET_FUNCTION_KEY = new Method("getFunction",
106                            Types.OBJECT,
107                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY});
108        // Object getFunctionWithNamedValues (Object,String,Object[])
109        private final static Method GET_FUNCTION_WITH_NAMED_ARGS_KEY = new Method("getFunctionWithNamedValues",
110                            Types.OBJECT,
111                            new Type[]{Types.OBJECT,Types.COLLECTION_KEY,Types.OBJECT_ARRAY});
112            
113            private static final Type VARIABLE_UTIL_IMPL = Type.getType(VariableUtilImpl.class);
114            
115        private static final Method RECORDCOUNT = new Method("recordcount",
116                            Types.OBJECT,
117                            new Type[]{Types.PAGE_CONTEXT,Types.OBJECT});
118            private static final Method CURRENTROW = new Method("currentrow",
119                            Types.OBJECT,
120                            new Type[]{Types.PAGE_CONTEXT,Types.OBJECT});
121            private static final Method COLUMNLIST = new Method("columnlist",
122                            Types.OBJECT,
123                            new Type[]{Types.PAGE_CONTEXT,Types.OBJECT});
124    
125            private static final Method THIS_GET = new Method("thisGet",
126                            Types.OBJECT,
127                            new Type[]{});
128            private static final Method THIS_TOUCH = new Method("thisTouch",
129                            Types.OBJECT,
130                            new Type[]{});
131        
132        
133            int scope=Scope.SCOPE_UNDEFINED;
134            List<Member> members=new ArrayList<Member>();
135            int countDM=0;
136            int countFM=0;
137            private boolean ignoredFirstMember;
138    
139            private boolean fromHash=false;
140    
141            public Variable(Position start,Position end) {
142                    super(start,end);
143            }
144            
145            public Variable(int scope,Position start,Position end) {
146                    super(start,end);
147                    this.scope=scope;
148            }
149            
150            /**
151             * @return the scope
152             */
153            public int getScope() {
154                    return scope;
155            }
156    
157            /**
158             * @param scope the scope to set
159             */
160            public void setScope(int scope) {
161                    this.scope = scope;
162            }
163            
164            public void addMember(Member member) {
165                    if(member instanceof DataMember)countDM++;
166                    else countFM++;
167                    members.add(member);
168            }
169            
170            public final Type writeOutCollection(BytecodeContext bc, int mode) throws BytecodeException {
171            ExpressionUtil.visitLine(bc, getStart());
172            Type type = _writeOut(bc,mode, Boolean.TRUE);
173            ExpressionUtil.visitLine(bc, getEnd());
174            return type;
175        }
176    
177            public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException {
178                    return _writeOut(bc, mode, null);
179            }
180            private Type _writeOut(BytecodeContext bc, int mode,Boolean asCollection) throws BytecodeException {
181                    
182                    
183                    GeneratorAdapter adapter = bc.getAdapter();
184                    int count=countFM+countDM;
185                    
186                    // count 0
187            if(count==0) return _writeOutEmpty(bc);
188           
189            boolean doOnlyScope=scope==Scope.SCOPE_LOCAL;
190            
191            
192            //boolean last;
193            for(int i=doOnlyScope?0:1;i<count;i++) {
194                            adapter.loadArg(0);
195            }
196            
197            Type rtn=null;
198            // this.
199            if(scope==Scope.SCOPE_UNDEFINED && members.get(0) instanceof DataMember) {
200                    DataMember dm=(DataMember) members.get(0);
201                    ExprString name = dm.getName();
202                    if(ASMUtil.isDotKey(name)){
203                            LitString ls = (LitString)name;
204                                    if(ls.getString().equalsIgnoreCase("THIS")){
205                                            adapter.loadArg(0);
206                                            adapter.checkCast(Types.PAGE_CONTEXT_IMPL);
207                                adapter.invokeVirtual(Types.PAGE_CONTEXT_IMPL,count==1?THIS_GET:THIS_TOUCH);
208                                            rtn= Types.OBJECT;
209                                    }
210                    }
211            }
212            if(rtn==null)rtn=_writeOutFirst(bc, (members.get(0)),mode,count==1,doOnlyScope);
213                    
214                    // pc.get(
215                    for(int i=doOnlyScope?0:1;i<count;i++) {
216                            Member member=(members.get(i));
217                            boolean last=(i+1)==count;
218                            
219                            // Data Member
220                            if(member instanceof DataMember)        {
221                                    ExprString name = ((DataMember)member).getName();
222                                    if(last && ASMUtil.isDotKey(name)){
223                                            LitString ls = (LitString)name;
224                                            if(ls.getString().equalsIgnoreCase("RECORDCOUNT")){
225                                                    adapter.invokeStatic(VARIABLE_UTIL_IMPL, RECORDCOUNT);
226                                            }
227                                            else if(ls.getString().equalsIgnoreCase("CURRENTROW")){
228                                                    adapter.invokeStatic(VARIABLE_UTIL_IMPL, CURRENTROW);
229                                            }
230                                            else if(ls.getString().equalsIgnoreCase("COLUMNLIST")){
231                                                    adapter.invokeStatic(VARIABLE_UTIL_IMPL, COLUMNLIST);
232                                            }
233                                            else {
234                                                    
235                                                    if(registerKey(bc,name))adapter.invokeVirtual(Types.PAGE_CONTEXT,asCollection(asCollection, last)?GET_COLLECTION_KEY:GET_KEY);
236                                                    else adapter.invokeVirtual(Types.PAGE_CONTEXT,asCollection(asCollection, last)?GET_COLLECTION:GET);
237                                            }
238                                    }
239                                    else{
240                                            if(registerKey(bc,name))adapter.invokeVirtual(Types.PAGE_CONTEXT,asCollection(asCollection, last)?GET_COLLECTION_KEY:GET_KEY);
241                                            else adapter.invokeVirtual(Types.PAGE_CONTEXT,asCollection(asCollection, last)?GET_COLLECTION:GET);
242                                    }
243                                    rtn=Types.OBJECT;
244                            }
245    
246                            // UDF
247                            else if(member instanceof UDF) {
248                                    UDF udf=(UDF) member;
249                                    boolean isKey=registerKey(bc,udf.getName());
250                                    //udf.getName().writeOut(bc, MODE_REF);
251                                    ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, udf.getArguments());
252                                    
253                                    if(isKey) adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS_KEY:GET_FUNCTION_KEY);
254                                    else adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS:GET_FUNCTION);
255                                    rtn=Types.OBJECT;
256                            }
257            }
258            return rtn;
259            }
260            
261            private boolean asCollection(Boolean asCollection, boolean last) {
262                    if(!last) return true;
263                    return asCollection!=null && asCollection.booleanValue();
264            }
265    
266            public static boolean registerKey(BytecodeContext bc,Expression name) throws BytecodeException {
267                    return registerKey(bc, name, false);
268            }
269            
270    public static boolean registerKey(BytecodeContext bc,Expression name,boolean doUpperCase) throws BytecodeException {
271                    
272                    if(name instanceof Literal) {
273                            Literal l=(Literal) name;
274                            
275                            LitString ls = name instanceof LitString?(LitString)l:LitString.toLitString(l.getString());
276                            if(doUpperCase){
277                                    ls=ls.duplicate();
278                                    ls.upperCase();
279                            }
280                            String key=KeyConstants.getFieldName(ls.getString());
281                            if(key!=null){
282                                    bc.getAdapter().getStatic(KEY_CONSTANTS, key, Types.COLLECTION_KEY);
283                                    return true;
284                            }
285                            int index=bc.registerKey(ls);
286                            bc.getAdapter().visitVarInsn(Opcodes.ALOAD, 0);
287                            bc.getAdapter().visitFieldInsn(Opcodes.GETFIELD,  bc.getClassName(), "keys", Types.COLLECTION_KEY_ARRAY.toString());
288                            bc.getAdapter().push(index);
289                            bc.getAdapter().visitInsn(Opcodes.AALOAD);
290                            
291                            
292                            //ExpressionUtil.writeOutSilent(lit,bc, Expression.MODE_REF);
293                            //bc.getAdapter().invokeStatic(Page.KEY_IMPL, Page.KEY_INTERN);
294                            
295                            return true;
296                    }
297                    name.writeOut(bc, MODE_REF);
298                    return false;
299            }
300    
301            public static boolean canRegisterKey(Expression name) {
302                    return name instanceof LitString;
303            }
304    
305            
306            /**
307             * outputs a empty Variable, only scope 
308             * Example: pc.formScope();
309             * @param adapter
310             * @throws TemplateException
311             */
312            private Type _writeOutEmpty(BytecodeContext bc) throws BytecodeException {
313                    if(ignoredFirstMember && (scope==Scope.SCOPE_LOCAL || scope==ScopeSupport.SCOPE_VAR)) 
314                            return Types.VOID;
315                    
316                    
317                    GeneratorAdapter adapter = bc.getAdapter();
318                    adapter.loadArg(0);
319                    Method m;
320                    Type t=Types.PAGE_CONTEXT;
321                    if(scope==Scope.SCOPE_ARGUMENTS) {
322                            LitBoolean.TRUE.writeOut(bc, MODE_VALUE);
323                             m = TypeScope.METHOD_ARGUMENT_BIND;
324                    }
325                    else if(scope==Scope.SCOPE_LOCAL) {
326                            t=Types.PAGE_CONTEXT;
327                            LitBoolean.TRUE.writeOut(bc, MODE_VALUE);
328                             m = TypeScope.METHOD_LOCAL_BIND;
329                    }
330                    else if(scope==ScopeSupport.SCOPE_VAR) {
331                            t=Types.PAGE_CONTEXT;
332                            LitBoolean.TRUE.writeOut(bc, MODE_VALUE);
333                             m = TypeScope.METHOD_VAR_BIND;
334                    }
335                    else m = TypeScope.METHODS[scope]; 
336                    
337                    TypeScope.invokeScope(adapter,m,t);
338                    
339                    
340                    return m.getReturnType();
341            }
342            
343            
344    
345            private Type _writeOutFirst(BytecodeContext bc, Member member, int mode, boolean last, boolean doOnlyScope) throws BytecodeException {
346            if(member instanceof DataMember)
347                    return _writeOutFirstDataMember(bc,(DataMember)member, scope,last , doOnlyScope);
348            else if(member instanceof UDF)
349                    return _writeOutFirstUDF(bc,(UDF)member,scope,doOnlyScope);
350            else
351                    return _writeOutFirstBIF(bc,(BIF)member,mode,last,getStart());
352            }
353            
354            static Type _writeOutFirstBIF(BytecodeContext bc, BIF bif, int mode,boolean last,Position line) throws BytecodeException {
355            GeneratorAdapter adapter = bc.getAdapter();
356                    adapter.loadArg(0);
357                    // class
358                    Type bifClass = Types.toType(bif.getClassName());
359                    
360                    // arguments
361                    Argument[] args = bif.getArguments();
362                    Type[] argTypes;
363                    // Arg Type FIX
364                    if(bif.getArgType()==FunctionLibFunction.ARG_FIX)       {
365                            
366                            if(isNamed(bif.getName(),args)) {
367                                    NamedArgument[] nargs=toNamedArguments(args);
368                                    
369                                    String[] names=new String[nargs.length];
370                                    // get all names
371                                    for(int i=0;i<nargs.length;i++){
372                                            names[i] = getName(nargs[i].getName());
373                                    }
374                                    
375                                    
376                                    ArrayList<FunctionLibFunctionArg> list = bif.getFlf().getArg();
377                                    Iterator<FunctionLibFunctionArg> it = list.iterator();
378                                    
379                                    argTypes=new Type[list.size()+1];
380                                    argTypes[0]=Types.PAGE_CONTEXT;
381                                    
382                                    FunctionLibFunctionArg flfa;
383                                    int index=0;
384                                    VT vt;
385                                    while(it.hasNext()) {
386                                            flfa =it.next();
387                                            vt = getMatchingValueAndType(flfa,nargs,names,line);
388                                            if(vt.index!=-1) 
389                                                    names[vt.index]=null;
390                                            argTypes[++index]=Types.toType(vt.type);
391                                            if(vt.value==null)ASMConstants.NULL(bc.getAdapter());
392                                            else vt.value.writeOut(bc, Types.isPrimitiveType(argTypes[index])?MODE_VALUE:MODE_REF);
393                                    }
394                                    
395                                    for(int y=0;y<names.length;y++){
396                                            if(names[y]!=null) {
397                                                    BytecodeException bce = new BytecodeException("argument ["+names[y]+"] is not allowed for function ["+bif.getFlf().getName()+"]", args[y].getStart());
398                                                    UDFUtil.addFunctionDoc(bce, bif.getFlf());
399                                                    throw bce;
400                                            }
401                                    }
402                                    
403                            }
404                            else{
405                                    argTypes=new Type[args.length+1];
406                                    argTypes[0]=Types.PAGE_CONTEXT;
407                                    
408                                    
409                                    for(int y=0;y<args.length;y++) {
410                                            argTypes[y+1]=Types.toType(args[y].getStringType());
411                                            args[y].writeOutValue(bc, Types.isPrimitiveType(argTypes[y+1])?MODE_VALUE:MODE_REF);
412                                    }
413                            }
414                            
415                    }
416                    // Arg Type DYN
417                    else    {
418                            
419                            argTypes=new Type[2];
420                            argTypes[0]=Types.PAGE_CONTEXT;
421                            argTypes[1]=Types.OBJECT_ARRAY;
422                            ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, args); 
423                    }
424                    
425                    // return type
426                    Type rtnType=Types.toType(bif.getReturnType());
427                    if(rtnType==Types.VOID)rtnType=Types.STRING;
428                    adapter.        invokeStatic(bifClass,new Method("call",rtnType,argTypes));
429                    
430                    
431                    if(mode==MODE_REF || !last) {
432                            if(Types.isPrimitiveType(rtnType)) {
433                                    adapter.invokeStatic(Types.CASTER,new Method("toRef",Types.toRefType(rtnType),new Type[]{rtnType}));
434                                    rtnType=Types.toRefType(rtnType);
435                            }
436                    }
437                    return rtnType;
438            }
439                    
440            
441    
442            
443    
444            
445    
446            static Type _writeOutFirstUDF(BytecodeContext bc, UDF udf, int scope, boolean doOnlyScope) throws BytecodeException {
447    
448            GeneratorAdapter adapter = bc.getAdapter();
449                    // pc.getFunction (Object,String,Object[])
450                // pc.getFunctionWithNamedValues (Object,String,Object[])
451                    adapter.loadArg(0);
452                    if(!doOnlyScope)adapter.loadArg(0);
453                    Type rtn = TypeScope.invokeScope(adapter, scope);
454                    if(doOnlyScope) return rtn;
455                    
456                    boolean isKey=registerKey(bc,udf.getName());
457                    ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, udf.getArguments());
458                    if(isKey) adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS_KEY:GET_FUNCTION_KEY);
459                    else adapter.invokeVirtual(Types.PAGE_CONTEXT,udf.hasNamedArgs()?GET_FUNCTION_WITH_NAMED_ARGS:GET_FUNCTION);
460                    return Types.OBJECT;
461                    
462            }
463    
464            static Type _writeOutFirstDataMember(BytecodeContext bc, DataMember member, int scope, boolean last, boolean doOnlyScope) throws BytecodeException {
465            
466                    
467                    GeneratorAdapter adapter = bc.getAdapter();
468                    adapter.loadArg(0);
469                    Type rtn = TypeScope.invokeScope(adapter, scope);
470                    if(doOnlyScope) return rtn;
471                    
472                    if(registerKey(bc,member.getName()))
473                    adapter.invokeInterface(TypeScope.SCOPES[scope],!last && scope==Scope.SCOPE_UNDEFINED?METHOD_SCOPE_GET_COLLECTION_KEY:METHOD_SCOPE_GET_KEY);
474                    else
475                            adapter.invokeInterface(TypeScope.SCOPES[scope],!last && scope==Scope.SCOPE_UNDEFINED?METHOD_SCOPE_GET_COLLECTION:METHOD_SCOPE_GET);
476            return Types.OBJECT;
477            }
478            
479            
480    
481            /**
482             * @return the members
483             */
484            public List<Member> getMembers() {
485                    return members;
486            }
487    
488            /**
489             * @return the first member or null if there no member
490             */
491            public Member getFirstMember() {
492                    if(members.isEmpty()) return null;
493                    return members.get(0);
494            }
495    
496            /**
497             * @return the first member or null if there no member
498             */
499            public Member getLastMember() {
500                    if(members.isEmpty()) return null;
501                    return members.get(members.size()-1);
502            }
503    
504            public void ignoredFirstMember(boolean b) {
505                    this.ignoredFirstMember=b;
506            }
507            public boolean ignoredFirstMember() {
508                    return ignoredFirstMember;
509            }
510            
511            
512            
513    
514            private static VT getMatchingValueAndType(FunctionLibFunctionArg flfa, NamedArgument[] nargs,String[] names, Position line) throws BytecodeException {
515                    String flfan=flfa.getName();
516                    
517                    // first search if a argument match
518                    for(int i=0;i<nargs.length;i++){
519                            if(names[i]!=null && names[i].equalsIgnoreCase(flfan)) {
520                                    nargs[i].setValue(nargs[i].getRawValue(),flfa.getTypeAsString());
521                                    return new VT(nargs[i].getValue(),flfa.getTypeAsString(),i);
522                            }
523                    }
524                    
525                    // then check if a alias match
526                    String alias=flfa.getAlias();
527                    if(!StringUtil.isEmpty(alias)) {
528                            //String[] arrAlias = railo.runtime.type.List.toStringArray(railo.runtime.type.List.trimItems(railo.runtime.type.List.listToArrayRemoveEmpty(alias, ',')));
529                            for(int i=0;i<nargs.length;i++){
530                                    if(names[i]!=null && railo.runtime.type.util.ListUtil.listFindNoCase(alias, names[i])!=-1){
531                                            nargs[i].setValue(nargs[i].getRawValue(),flfa.getTypeAsString());
532                                            return new VT(nargs[i].getValue(),flfa.getTypeAsString(),i);
533                                    }
534                            }
535                    }
536                    
537                    // if not required return the default value
538                    if(!flfa.getRequired()) {
539                            String defaultValue = flfa.getDefaultValue();
540                            String type=flfa.getTypeAsString().toLowerCase();
541                            
542                            if(defaultValue==null) {
543                                    if(type.equals("boolean") || type.equals("bool")) 
544                                            return new VT(LitBoolean.FALSE,type,-1);
545                                    if(type.equals("number") || type.equals("numeric") || type.equals("double")) 
546                                            return new VT(LitDouble.ZERO,type,-1);
547                                    return new VT(null,type,-1);
548                            }
549                            return new VT(CastOther.toExpression(LitString.toExprString(defaultValue), type),type,-1);
550                    }
551                    BytecodeException be = new BytecodeException("missing required argument ["+flfan+"] for function ["+flfa.getFunction().getName()+"]",line);
552                    UDFUtil.addFunctionDoc(be, flfa.getFunction());
553                    throw be;
554            }
555            
556            
557            
558    
559            private static String getName(Expression expr) throws BytecodeException {
560                    String name = ASMUtil.toString(expr);
561                    if(name==null) throw new BytecodeException("cannot extract a string from a object of type ["+expr.getClass().getName()+"]",null);
562                    return name;
563            }
564    
565            /**
566             * translate a array of arguments to a araay of NamedArguments, attention no check if the elements are really  named arguments
567             * @param args
568             * @return
569             */
570            private static NamedArgument[] toNamedArguments(Argument[] args) {
571                    NamedArgument[] nargs=new NamedArgument[args.length];
572                    for(int i=0;i<args.length;i++){
573                            nargs[i]=(NamedArgument) args[i];
574                    }
575                    
576                    return nargs;
577            }
578    
579            
580    
581            /**
582             * check if the arguments are named arguments or regular arguments, throws a exception when mixed
583             * @param funcName
584             * @param args
585             * @param line
586             * @return
587             * @throws BytecodeException
588             */
589            private static  boolean isNamed(Object funcName,Argument[] args) throws BytecodeException {
590                    if(ArrayUtil.isEmpty(args)) return false;
591                    boolean named=false;
592                    for(int i=0;i<args.length;i++){
593                            if(args[i] instanceof NamedArgument)named=true;
594                            else if(named)
595                                    throw new BytecodeException("invalid argument for function "+funcName+", you can not mix named and unnamed arguments", args[i].getStart());
596                    }
597                    
598                    
599                    return named;
600            }
601    
602            public void setFromHash(boolean fromHash) {
603                    this.fromHash=fromHash;
604            }
605    
606            public boolean fromHash() {
607                    return fromHash;
608            }
609            
610    }
611    
612    class VT{
613            Expression value;
614            String type;
615            int index;
616    
617            public VT(Expression value, String type, int index) {
618                    this.value=value;
619                    this.type=type;
620                    this.index=index;
621            }
622    }