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 }