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