001    package railo.transformer.bytecode.statement;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    import org.objectweb.asm.ClassWriter;
009    import org.objectweb.asm.Opcodes;
010    import org.objectweb.asm.Type;
011    import org.objectweb.asm.commons.GeneratorAdapter;
012    import org.objectweb.asm.commons.Method;
013    
014    import railo.commons.lang.CFTypes;
015    import railo.commons.lang.StringUtil;
016    import railo.runtime.Component;
017    import railo.runtime.exp.TemplateException;
018    import railo.runtime.type.FunctionArgument;
019    import railo.runtime.type.FunctionArgumentImpl;
020    import railo.runtime.type.FunctionArgumentLight;
021    import railo.runtime.type.util.ComponentUtil;
022    import railo.transformer.bytecode.Body;
023    import railo.transformer.bytecode.BytecodeContext;
024    import railo.transformer.bytecode.BytecodeException;
025    import railo.transformer.bytecode.Page;
026    import railo.transformer.bytecode.cast.CastBoolean;
027    import railo.transformer.bytecode.cast.CastString;
028    import railo.transformer.bytecode.expression.ExprBoolean;
029    import railo.transformer.bytecode.expression.ExprString;
030    import railo.transformer.bytecode.expression.Expression;
031    import railo.transformer.bytecode.expression.var.Variable;
032    import railo.transformer.bytecode.literal.LitBoolean;
033    import railo.transformer.bytecode.literal.LitInteger;
034    import railo.transformer.bytecode.literal.LitString;
035    import railo.transformer.bytecode.statement.tag.Attribute;
036    import railo.transformer.bytecode.util.ASMConstants;
037    import railo.transformer.bytecode.util.ASMUtil;
038    import railo.transformer.bytecode.util.ExpressionUtil;
039    import railo.transformer.bytecode.util.Types;
040    
041    public final class Function extends StatementBase implements Opcodes, IFunction,HasBody {
042    
043            
044            
045            // Scope variablesScope()
046            private static final Method VARIABLE_SCOPE = new Method(
047                            "variablesScope",
048                            Types.VARIABLES,
049                            new Type[]{}
050                    );
051    
052    
053            // Object set(String,Object)
054            private static final Method SET_STR = new Method(
055                            "set",
056                            Types.OBJECT,
057                            new Type[]{Types.STRING,Types.OBJECT}
058                    );
059            
060            private static final Method SET_KEY = new Method(
061                            "set",
062                            Types.OBJECT,
063                            new Type[]{Types.COLLECTION_KEY,Types.OBJECT}
064                    );
065            
066            private static final Method REG_UDF_STR = new Method(
067                            "registerUDF",
068                            Types.VOID,
069                            new Type[]{Types.STRING,Types.UDF_PROPERTIES}
070                    );
071    
072            
073            private static final Method REG_UDF_KEY = new Method(
074                            "registerUDF",
075                            Types.VOID,
076                            new Type[]{Types.COLLECTION_KEY,Types.UDF_PROPERTIES}
077                    );
078    
079            
080            
081            private static final ExprString ANY = LitString.toExprString("any");
082            //private static final ExprString PUBLIC = LitString.toExprString("public");
083            //private static final ExprString EMPTY = LitString.toExprString("");
084    
085    
086            private static final Type UDF_PROPERTIES = Type.getType(railo.runtime.type.UDFProperties.class);
087    
088            // <init>(Page,FunctionArgument[],int String,String,boolean);
089            private static final Type FUNCTION_ARGUMENT = Type.getType(FunctionArgument.class);
090            private static final Type FUNCTION_ARGUMENT_IMPL = Type.getType(FunctionArgumentImpl.class);
091            private static final Type FUNCTION_ARGUMENT_LIGHT = Type.getType(FunctionArgumentLight.class);
092            private static final Type FUNCTION_ARGUMENT_ARRAY = Type.getType(FunctionArgument[].class);
093            
094            private static final Method INIT_UDF_IMPL_PROP = new Method(
095                            "<init>",
096                            Types.VOID,
097                            new Type[]{
098                                            Types.UDF_PROPERTIES
099                                    }
100                    );
101            
102            
103            private static final Method INIT_UDF_PROPERTIES_STRTYPE = new Method(
104                            "<init>",
105                            Types.VOID,
106                            new Type[]{
107                                            Types.PAGE_SOURCE,
108                                            FUNCTION_ARGUMENT_ARRAY,
109                                            Types.INT_VALUE,
110                                            Types.STRING,
111                                            Types.STRING,
112                                            Types.STRING,
113                                            Types.BOOLEAN_VALUE,
114                                            Types.BOOLEAN_VALUE,
115                                            Types.INT_VALUE,
116                                            Types.STRING,
117                                            Types.STRING,
118                                            Types.STRING,
119                                            Types.BOOLEAN,
120                                            Types.BOOLEAN,
121                                            Page.STRUCT_IMPL
122                                    }
123                    );
124            private static final Method INIT_UDF_PROPERTIES_SHORTTYPE = new Method(
125                            "<init>",
126                            Types.VOID,
127                            new Type[]{
128                                            Types.PAGE_SOURCE,
129                                            FUNCTION_ARGUMENT_ARRAY,
130                                            Types.INT_VALUE,
131                                            Types.STRING,
132                                            Types.SHORT_VALUE,
133                                            Types.STRING,
134                                            Types.BOOLEAN_VALUE,
135                                            Types.BOOLEAN_VALUE,
136                                            Types.INT_VALUE,
137                                            Types.STRING,
138                                            Types.STRING,
139                                            Types.STRING,
140                                            Types.BOOLEAN,
141                                            Types.BOOLEAN,
142                                            Page.STRUCT_IMPL
143                                    }
144                    );
145    
146    
147            // FunctionArgumentImpl(String name,String type,boolean required,int defaultType,String dspName,String hint,StructImpl meta)
148            private static final Method INIT_FAI_STRING = new Method(
149                            "<init>",
150                            Types.VOID,
151                            new Type[]{Types.STRING,        Types.STRING,Types.SHORT_VALUE,Types.BOOLEAN_VALUE,Types.INT_VALUE,Types.BOOLEAN_VALUE,Types.STRING,Types.STRING,Page.STRUCT_IMPL}
152                    );      
153            private static final Method INIT_FAI_KEY1 = new Method(
154                            "<init>",
155                            Types.VOID,
156                            new Type[]{
157                                            Types.COLLECTION_KEY}
158                    );      
159            private static final Method INIT_FAI_KEY3 = new Method(
160                            "<init>",
161                            Types.VOID,
162                            new Type[]{
163                                            Types.COLLECTION_KEY,
164                                            Types.STRING,
165                                            Types.SHORT_VALUE}
166                    );
167            private static final Method INIT_FAI_KEY4 = new Method(
168                            "<init>",
169                            Types.VOID,
170                            new Type[]{
171                                            Types.COLLECTION_KEY,
172                                            Types.STRING,
173                                            Types.SHORT_VALUE,
174                                            Types.BOOLEAN_VALUE}
175                    );      
176            private static final Method INIT_FAI_KEY5 = new Method(
177                            "<init>",
178                            Types.VOID,
179                            new Type[]{
180                                            Types.COLLECTION_KEY,
181                                            Types.STRING,
182                                            Types.SHORT_VALUE,
183                                            Types.BOOLEAN_VALUE,
184                                            Types.INT_VALUE}
185                    );
186            private static final Method INIT_FAI_KEY6 = new Method(
187                            "<init>",
188                            Types.VOID,
189                            new Type[]{
190                                            Types.COLLECTION_KEY,
191                                            Types.STRING,
192                                            Types.SHORT_VALUE,
193                                            Types.BOOLEAN_VALUE,
194                                            Types.INT_VALUE,
195                                            Types.BOOLEAN_VALUE}
196                    );
197            private static final Method INIT_FAI_KEY7 = new Method(
198                            "<init>",
199                            Types.VOID,
200                            new Type[]{
201                                            Types.COLLECTION_KEY,
202                                            Types.STRING,
203                                            Types.SHORT_VALUE,
204                                            Types.BOOLEAN_VALUE,
205                                            Types.INT_VALUE,
206                                            Types.BOOLEAN_VALUE,
207                                            Types.STRING}
208                    );
209            private static final Method INIT_FAI_KEY8 = new Method(
210                            "<init>",
211                            Types.VOID,
212                            new Type[]{
213                                            Types.COLLECTION_KEY,
214                                            Types.STRING,
215                                            Types.SHORT_VALUE,
216                                            Types.BOOLEAN_VALUE,
217                                            Types.INT_VALUE,
218                                            Types.BOOLEAN_VALUE,
219                                            Types.STRING,
220                                            Types.STRING}
221                    );
222            private static final Method INIT_FAI_KEY9 = new Method(
223                            "<init>",
224                            Types.VOID,
225                            new Type[]{
226                                            Types.COLLECTION_KEY,
227                                            Types.STRING,
228                                            Types.SHORT_VALUE,
229                                            Types.BOOLEAN_VALUE,
230                                            Types.INT_VALUE,
231                                            Types.BOOLEAN_VALUE,
232                                            Types.STRING,
233                                            Types.STRING,
234                                            Page.STRUCT_IMPL}
235                    );      
236            private static final Method[] INIT_FAI_KEY=new Method[]{
237                    INIT_FAI_KEY1,INIT_FAI_KEY3,INIT_FAI_KEY4,INIT_FAI_KEY5,INIT_FAI_KEY6,INIT_FAI_KEY7,INIT_FAI_KEY8,INIT_FAI_KEY9
238            };
239            private static final Method[] INIT_FAI_KEY_LIGHT=new Method[]{
240                    INIT_FAI_KEY1,INIT_FAI_KEY3
241            };
242            
243            
244            private ExprString name;
245            private ExprString returnType=ANY;
246            private ExprBoolean output=LitBoolean.TRUE;
247            private ExprBoolean abstr=LitBoolean.FALSE;
248            private int access=Component.ACCESS_PUBLIC;
249            private ExprString displayName=LitString.EMPTY;
250            private ExprString hint=LitString.EMPTY;
251            private Body body;
252            private List<Argument> arguments=new ArrayList<Argument>();
253            private Map<String,Attribute> metadata;
254            private ExprString returnFormat;
255            private ExprString description;
256            private ExprBoolean secureJson;
257            private ExprBoolean verifyClient;
258    
259            public Function(String name,int access,String returnType,Body body,int startline,int endline) {
260                    super(startline,endline);
261                    this.name=LitString.toExprString(name, -1);
262                    this.access=access;
263                    if(!StringUtil.isEmpty(returnType))this.returnType=LitString.toExprString(returnType);
264                    
265                    this.body=body;
266                    body.setParent(this);
267                    
268                    
269            }
270            
271            public Function(Expression name,Expression returnType,Expression returnFormat,Expression output,Expression abstr,
272                            int access,Expression displayName,Expression description,Expression hint,Expression secureJson,
273                            Expression verifyClient,Body body,int startline,int endline) {
274                    super(startline,endline);
275                    this.name=CastString.toExprString(name);
276                    this.returnType=CastString.toExprString(returnType);
277                    this.returnFormat=returnFormat!=null?CastString.toExprString(returnFormat):null;
278                    this.output=CastBoolean.toExprBoolean(output);
279                    this.abstr=CastBoolean.toExprBoolean(abstr);
280                    this.access=access;
281                    this.description=description!=null?CastString.toExprString(description):null;
282                    this.displayName=CastString.toExprString(displayName);
283                    this.hint=CastString.toExprString(hint);
284                    this.secureJson=secureJson!=null?CastBoolean.toExprBoolean(secureJson):null;
285                    this.verifyClient=verifyClient!=null?CastBoolean.toExprBoolean(verifyClient):null;
286                    //checkNameConflict(this.name);
287    
288                    
289                    this.body=body;
290                    body.setParent(this);
291                    
292            }
293    
294    
295            /*private static void checkNameConflict(ExprString expr) {
296                    if(expr instanceof LitString){
297                            String name=((LitString)expr).getString();
298                            if()
299                    }
300            }*/
301    
302            /**
303             * @see railo.transformer.bytecode.statement.IFunction#writeOut(railo.transformer.bytecode.BytecodeContext, int)
304             */
305            public void writeOut(BytecodeContext bc, int type) throws BytecodeException {
306            ExpressionUtil.visitLine(bc, getStartLine());
307            _writeOut(bc,type);
308            ExpressionUtil.visitLine(bc, getEndLine());
309            }
310            
311            /**
312             * @see railo.transformer.bytecode.statement.StatementBase#_writeOut(railo.transformer.bytecode.BytecodeContext)
313             */
314            public void _writeOut(BytecodeContext bc) throws BytecodeException {
315                    _writeOut(bc,PAGE_TYPE_REGULAR);
316            }
317            
318            public void _writeOut(BytecodeContext bc, int pageType) throws BytecodeException {
319                    
320                    GeneratorAdapter adapter = bc.getAdapter();
321                    Page page = ASMUtil.getAncestorPage(this);
322                    int index=page.addFunction(this);
323    
324                    // c.set(<name>,udf);
325                    if(pageType==PAGE_TYPE_INTERFACE) {
326                            adapter.loadArg(0);
327                    }
328                    else if(pageType==PAGE_TYPE_COMPONENT) {
329                            adapter.loadArg(1);
330                    }
331                    // pc.variablesScope().set(<name>,udf);
332                    else {
333                            adapter.loadArg(0);
334                            adapter.invokeVirtual(Types.PAGE_CONTEXT, VARIABLE_SCOPE);
335                    }
336                    boolean hasKey = Variable.registerKey(bc,name,true);
337                    //name.writeOut(bc, Expression.MODE_REF);
338                    
339                    // CHANGES
340                    //loadUDF(bc,index);
341                    //loadUDFProperties(bc,index);
342                    //createUDF(bc,index);
343                    
344                    if(pageType==PAGE_TYPE_COMPONENT) {
345                            loadUDF(bc,index,true);
346                            adapter.invokeVirtual(Types.COMPONENT_IMPL, hasKey?REG_UDF_KEY:REG_UDF_STR);
347                    }
348                    else if(pageType==PAGE_TYPE_INTERFACE) {
349                            loadUDF(bc,index,true);
350                            adapter.invokeVirtual(Types.INTERFACE_IMPL, hasKey?REG_UDF_KEY:REG_UDF_STR);
351                    }
352                    else {
353                            loadUDF(bc, index);
354                            adapter.invokeInterface(Types.VARIABLES, hasKey?SET_KEY:SET_STR);
355                            adapter.pop();
356                    }
357            }
358    
359            public void loadUDF(BytecodeContext bc, int index, boolean onlyProps) throws BytecodeException {
360                    BytecodeContext constr = bc.getConstructor();
361                    ClassWriter cw = bc.getClassWriter();
362                    //String type = Type.getType(UDFProperties.class).toString();
363                    String type = onlyProps?Types.UDF_PROPERTIES.toString():Types.UDF_IMPL.toString();
364                    String str="u"+index;
365                    GeneratorAdapter cga = constr.getAdapter();
366                    GeneratorAdapter ga = bc.getAdapter();
367                    
368                    // store
369                    cga.visitVarInsn(ALOAD, 0);
370                    cga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", onlyProps?Types.UDF_PROPERTIES_ARRAY.toString():Types.UDF_IMPL_ARRAY.toString());
371                    cga.push(index);
372                    createUDFProperties(constr,index,onlyProps);
373                    //cga.visitInsn(DUP_X2);
374                    cga.visitInsn(AASTORE);
375                    
376                    // get
377                    ga.visitVarInsn(ALOAD, 0);
378                    ga.visitFieldInsn(GETFIELD, bc.getClassName(), "udfs", onlyProps?Types.UDF_PROPERTIES_ARRAY.toString():Types.UDF_IMPL_ARRAY.toString());
379                    ga.push(index);
380                    ga.visitInsn(AALOAD);
381            }
382            
383            
384            
385            public void createUDFProperties(BytecodeContext bc, int index, boolean onlyProps) throws BytecodeException {
386                    GeneratorAdapter adapter=bc.getAdapter();
387                    if(!onlyProps) {
388                            adapter.newInstance(Types.UDF_IMPL);
389                            adapter.dup();
390                    }
391                    adapter.newInstance(UDF_PROPERTIES);
392                    adapter.dup();
393                    adapter.visitVarInsn(ALOAD, 1);
394                    // page
395                    //adapter.loadLocal(0);
396                    //adapter.loadThis();
397                    
398                    // arguments
399                    createArguments(bc);
400                    // index
401                    adapter.push(index);
402                    // name
403                    ExpressionUtil.writeOutSilent(name,bc, Expression.MODE_REF);
404                    // return type
405                    short type=ExpressionUtil.toShortType(returnType,CFTypes.TYPE_UNKNOW);
406                    if(type==CFTypes.TYPE_UNKNOW) ExpressionUtil.writeOutSilent(returnType,bc, Expression.MODE_REF);
407                    else adapter.push(type);
408                    // return format
409                    if(returnFormat!=null)ExpressionUtil.writeOutSilent(returnFormat,bc, Expression.MODE_REF);
410                    else ASMConstants.NULL(adapter);
411                    // output
412                    ExpressionUtil.writeOutSilent(output,bc, Expression.MODE_VALUE);
413                    // abstract
414                    ExpressionUtil.writeOutSilent(abstr,bc, Expression.MODE_VALUE);
415                    // access
416                    writeOutAccess(bc, access);
417                    // displayName
418                    ExpressionUtil.writeOutSilent(displayName,bc, Expression.MODE_REF);// displayName;
419                    // description
420                    if(description!=null)ExpressionUtil.writeOutSilent(description,bc, Expression.MODE_REF);// displayName;
421                    else adapter.push("");
422                    // hint
423                    ExpressionUtil.writeOutSilent(hint,bc, Expression.MODE_REF);// hint;
424                    // secureJson
425                    if(secureJson!=null)ExpressionUtil.writeOutSilent(secureJson,bc, Expression.MODE_REF);
426                    else ASMConstants.NULL(adapter);
427                    // verify client
428                    if(verifyClient!=null)ExpressionUtil.writeOutSilent(verifyClient,bc, Expression.MODE_REF);
429                    else ASMConstants.NULL(adapter);
430                    // meta
431                    Page.createMetaDataStruct(bc,metadata,null);
432                    
433                    adapter.invokeConstructor(UDF_PROPERTIES, type==-1?INIT_UDF_PROPERTIES_STRTYPE:INIT_UDF_PROPERTIES_SHORTTYPE);
434                    if(!onlyProps)adapter.invokeConstructor(Types.UDF_IMPL, INIT_UDF_IMPL_PROP);
435                    
436            }
437            
438            public void loadUDF(BytecodeContext bc, int index) throws BytecodeException {
439                    // new UDF(...)
440                    GeneratorAdapter adapter=bc.getAdapter();
441                    adapter.newInstance(Types.UDF_IMPL);
442                    adapter.dup();
443                    
444                    loadUDF(bc, index,true);
445                    
446                    adapter.invokeConstructor(Types.UDF_IMPL, INIT_UDF_IMPL_PROP);
447            }
448            
449            
450    
451            /*private void loadArguments(BytecodeContext bc, int index) throws BytecodeException {
452                    BytecodeContext constr = bc.getStaticConstructor();
453                    String type = Type.getType(FunctionArgument[].class).toString();
454                    String fa="fa_"+index;
455                    FieldVisitor fv = constr.getClassWriter().visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, 
456                                    fa, type, null, null);
457                    fv.visitEnd();
458                    createArguments(constr);
459                    constr.getAdapter().visitFieldInsn(Opcodes.PUTSTATIC, constr.getClassName(), fa, type);
460                    
461                    bc.getAdapter().visitFieldInsn(Opcodes.GETSTATIC, constr.getClassName(), fa, type);
462                    //createArguments(bc, adapter);
463                    
464                    
465            }*/
466            
467            private void createArguments(BytecodeContext bc) throws BytecodeException {
468                    GeneratorAdapter ga = bc.getAdapter();
469                    ga.push(arguments.size());
470                    ga.newArray(FUNCTION_ARGUMENT);
471                    Argument arg;
472            for (int i = 0; i < arguments.size(); i++) {
473                    arg=(Argument) arguments.get(i);
474                
475                    boolean canHaveKey = Variable.canRegisterKey(arg.getName());
476                    
477            // CHECK if default values
478                    // type
479                    ExprString _strType = arg.getType();
480                    short _type=CFTypes.TYPE_UNKNOW;
481                    if(_strType instanceof LitString){
482                            _type=CFTypes.toShortStrict(((LitString)_strType).getString(),CFTypes.TYPE_UNKNOW);
483                    }
484                    boolean useType=!canHaveKey || _type!=CFTypes.TYPE_ANY;
485                    //boolean useStrType=useType && (_type==CFTypes.TYPE_UNDEFINED || _type==CFTypes.TYPE_UNKNOW || CFTypes.toString(_type, null)==null);
486                    
487                    // required
488                    ExprBoolean _req = arg.getRequired();
489                    boolean useReq=!canHaveKey || toBoolean(_req,null)!=Boolean.FALSE;
490                    
491                    // default-type
492                    Expression _def = arg.getDefaultValueType();
493                    boolean useDef=!canHaveKey || toInt(_def,-1)!=FunctionArgument.DEFAULT_TYPE_NULL;
494                    
495                    // pass by reference
496                    ExprBoolean _pass = arg.isPassByReference();
497                    boolean usePass=!canHaveKey || toBoolean(_pass,null)!=Boolean.TRUE;
498                    
499                    // display-hint
500                    ExprString _dsp = arg.getDisplayName();
501                    boolean useDsp=!canHaveKey || !isLiteralEmptyString(_dsp);
502                    
503                    // hint
504                    ExprString _hint = arg.getHint();
505                    boolean useHint=!canHaveKey || !isLiteralEmptyString(_hint);
506                    
507                    // meta
508                    Map _meta = arg.getMetaData();
509                    boolean useMeta=!canHaveKey || (_meta!=null && !_meta.isEmpty());
510                    int functionIndex=7;
511                    if(!useMeta) {
512                            functionIndex--;
513                            if(!useHint) {
514                                    functionIndex--;
515                                    if(!useDsp){
516                                            functionIndex--;
517                                            if(!usePass) {
518                                                    functionIndex--;
519                                                    if(!useDef) {
520                                                            functionIndex--;
521                                                            if(!useReq) {
522                                                                    functionIndex--;
523                                                                    if(!useType){
524                                                                            functionIndex--;
525                                                                    }
526                                                            }
527                                                    }
528                                            }
529                                    }
530                            }
531                    }
532            // write out arguments  
533                    ga.dup();
534                ga.push(i);
535                    
536                // new FunctionArgument(...)
537                ga.newInstance(canHaveKey && functionIndex<INIT_FAI_KEY_LIGHT.length?FUNCTION_ARGUMENT_LIGHT:FUNCTION_ARGUMENT_IMPL);
538                    ga.dup();
539                    boolean hasKey = Variable.registerKey(bc,arg.getName(),false);
540                    
541                    // type
542                    if(functionIndex>=INIT_FAI_KEY.length-7) {
543                            _strType.writeOut(bc, Expression.MODE_REF);
544                            bc.getAdapter().push(_type);
545                    }
546                    // required
547                    if(functionIndex>=INIT_FAI_KEY.length-6)_req.writeOut(bc, Expression.MODE_VALUE);
548                    // default value
549                    if(functionIndex>=INIT_FAI_KEY.length-5)_def.writeOut(bc, Expression.MODE_VALUE);
550                    // pass by reference
551                    if(functionIndex>=INIT_FAI_KEY.length-4)_pass.writeOut(bc, Expression.MODE_VALUE);
552                    // display-name
553                    if(functionIndex>=INIT_FAI_KEY.length-3)_dsp.writeOut(bc, Expression.MODE_REF);
554                    // hint
555                    if(functionIndex>=INIT_FAI_KEY.length-2)_hint.writeOut(bc, Expression.MODE_REF);
556                    //meta
557                    if(functionIndex==INIT_FAI_KEY.length-1)Page.createMetaDataStruct(bc,_meta,null);
558                    
559                    if(hasKey && functionIndex<INIT_FAI_KEY_LIGHT.length)
560                            ga.invokeConstructor(FUNCTION_ARGUMENT_LIGHT, INIT_FAI_KEY[functionIndex]);
561                    else 
562                            ga.invokeConstructor(FUNCTION_ARGUMENT_IMPL, hasKey?INIT_FAI_KEY[functionIndex]:INIT_FAI_STRING);
563    
564                ga.visitInsn(Opcodes.AASTORE);
565            }
566            }
567    
568            private int toInt(Expression expr, int defaultValue) {
569                    if(expr instanceof LitInteger) {
570                            return ((LitInteger)expr).getInteger().intValue();
571                    }
572                    return defaultValue;
573            }
574    
575            private Boolean toBoolean(ExprBoolean expr, Boolean defaultValue) {
576                    if(expr instanceof LitBoolean) {
577                            return ((LitBoolean)expr).getBooleanValue()?Boolean.TRUE:Boolean.FALSE;
578                    }
579                    return defaultValue;
580            }
581    
582            private boolean isLiteralEmptyString(ExprString expr) {
583                    if(expr instanceof LitString) {
584                            return StringUtil.isEmpty(((LitString)expr).getString());
585                    }
586                    return false;
587            }
588    
589            private void writeOutAccess(BytecodeContext bc,ExprString expr) {
590                    
591                    // write short type
592                    if(expr instanceof LitString){
593                            int access=ComponentUtil.toIntAccess(((LitString)expr).getString(),Component.ACCESS_PUBLIC);
594                            bc.getAdapter().push(access);
595                    }
596                    else bc.getAdapter().push(Component.ACCESS_PUBLIC);
597            }
598            private void writeOutAccess(BytecodeContext bc,int access) {
599                    bc.getAdapter().push(access);
600            }
601    
602            public void addArgument(String name, String type, boolean required, Expression defaultValue) {
603                    addArgument(
604                                    LitString.toExprString(name), 
605                                    LitString.toExprString(type), 
606                                    LitBoolean.toExprBoolean(required),
607                                    defaultValue, 
608                                    LitBoolean.TRUE,
609                                    LitString.EMPTY,
610                                    LitString.EMPTY,null);
611            }
612    
613            public void addArgument(Expression name, Expression type, Expression required, Expression defaultValue,ExprBoolean passByReference, 
614                            Expression displayName, Expression hint,Map meta) {
615                    arguments.add(new Argument(name,type,required,defaultValue,passByReference,displayName,hint,meta));
616            }
617    
618            /**
619             * @return the arguments
620             */
621            public List getArguments() {
622                    return arguments;
623            }
624    
625            /**
626             * @return the body
627             */
628            public Body getBody() {
629                    return body;
630            }
631    
632            public void setMetaData(Map<String,Attribute> metadata) {
633                    this.metadata=metadata;
634            }
635            
636            public void setHint(String hint){
637                    this.hint=LitString.toExprString(hint);
638            }
639    
640            public void addAttribute(Attribute attr) throws TemplateException {
641                    String name=attr.getName().toLowerCase();
642                    // name
643                    if("name".equals(name)) {
644                            throw new BytecodeException("name cannot be defined twice",getLine());
645                            //this.name=CastString.toExprString(attr.getValue());
646                    }
647                    else if("returntype".equals(name))      {
648                            this.returnType=toLitString(name,attr.getValue());
649                    }
650                    else if("access".equals(name))  {
651                            
652                            LitString ls = toLitString(name,attr.getValue());
653                            String strAccess = ls.getString();
654                            int acc = ComponentUtil.toIntAccess(strAccess,-1);
655                            if(acc==-1)
656                                    throw new BytecodeException("invalid access type ["+strAccess+"], access types are remote, public, package, private",getLine());
657                            access=acc;
658                            
659                    }
660                    
661                    else if("output".equals(name))          this.output=toLitBoolean(name,attr.getValue());
662                    else if("abstract".equals(name))        this.abstr=toLitBoolean(name,attr.getValue());
663                    else if("displayname".equals(name))     this.displayName=toLitString(name,attr.getValue());
664                    else if("hint".equals(name))            this.hint=toLitString(name,attr.getValue());
665                    else if("description".equals(name))     this.description=toLitString(name,attr.getValue());
666                    else if("returnformat".equals(name))this.returnFormat=toLitString(name,attr.getValue());
667                    else if("securejson".equals(name))      this.secureJson=toLitBoolean(name,attr.getValue());
668                    else if("verifyclient".equals(name))    this.verifyClient=toLitBoolean(name,attr.getValue());
669                    else {
670                            toLitString(name,attr.getValue());// needed for testing
671                            if(metadata==null)metadata=new HashMap();
672                            metadata.put(attr.getName(), attr);
673                    }
674            }
675    
676            private LitString toLitString(String name, Expression value) throws BytecodeException {
677                    ExprString es = CastString.toExprString(value);
678                    if(!(es instanceof LitString))
679                            throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getLine());
680                    return (LitString) es;
681            }
682            
683            private LitBoolean toLitBoolean(String name, Expression value) throws BytecodeException {
684                     ExprBoolean eb = CastBoolean.toExprBoolean(value);
685                    if(!(eb instanceof LitBoolean))
686                            throw new BytecodeException("value of attribute ["+name+"] must have a literal/constant value",getLine());
687                    return (LitBoolean) eb;
688            }
689    
690    }