1 package gnu.kawa.functions; 2 import gnu.bytecode.*; 3 import gnu.mapping.*; 4 import gnu.kawa.reflect.*; 5 import gnu.expr.*; 6 import java.io.*; 7 import kawa.lang.Translator; 8 9 10 11 public class GetNamedPart extends Procedure2 implements HasSetter, CanInline 12 { 13 public static final GetNamedPart getNamedPart = new GetNamedPart(); 14 15 16 public static final String CLASSTYPE_FOR = "<>"; 17 18 19 public static final String CAST_METHOD_NAME = "@"; 20 21 22 public static final String INSTANCEOF_METHOD_NAME = "instance?"; 23 24 public static String combineName (Expression part1, Expression part2) 25 { 26 String name1; 27 Object name2; 28 if (part2 instanceof QuoteExp 29 && (name2 = ((QuoteExp) part2).getValue()) instanceof String 30 && ((part1 instanceof ReferenceExp 31 && (name1 = ((ReferenceExp) part1).getSimpleName()) != null) 32 || (part1 instanceof GetNamedExp 33 && (name1 = ((GetNamedExp) part1).combinedName) != null))) 34 return (name1+':'+name2).intern(); 35 return null; 36 } 37 38 public static Expression makeExp (Expression clas, Expression member) 39 { 40 ReferenceExp rexp; 41 String combinedName = combineName(clas, member); 42 if (combinedName != null) 43 { 44 Translator tr = (Translator) Compilation.getCurrent(); 45 Declaration decl = tr.lexical.lookup(combinedName, false); 46 if (! Declaration.isUnknown(decl)) 47 return new ReferenceExp(decl); 48 49 Environment env = Environment.getCurrent(); 50 Symbol symbol = env.defaultNamespace().lookup(combinedName); 51 Object property = null; if (symbol != null && env.isBound(symbol, property)) 53 return new ReferenceExp(combinedName); 54 } 55 if (clas instanceof ReferenceExp 56 && (rexp = (ReferenceExp) clas).isUnknown()) 57 { 58 String name = rexp.getName(); 59 try 60 { 61 62 Class cl = Class.forName(name, false, 63 clas.getClass().getClassLoader()); 64 65 67 clas = QuoteExp.getInstance(Type.make(cl)); 68 } 69 catch (Throwable ex) 70 { 71 } 72 } 73 Expression[] args = { clas, member }; 74 GetNamedExp exp = new GetNamedExp(args); 75 exp.combinedName = combinedName; 76 return exp; 77 } 78 79 public static Expression makeExp (Expression clas, String member) 80 { 81 return makeExp(clas, new QuoteExp(member)); 82 } 83 84 public static Expression makeExp (Type type, String member) 85 { 86 return makeExp(new QuoteExp(type), new QuoteExp(member)); 87 } 88 89 public Expression inline (ApplyExp exp, ExpWalker walker) 90 { 91 Expression[] args = exp.getArgs(); 92 if (args.length != 2 || ! (args[1] instanceof QuoteExp) 93 || ! (exp instanceof GetNamedExp)) 94 return exp; 95 Expression context = args[0]; 96 Declaration decl = null; 97 if (context instanceof ReferenceExp) 98 { 99 ReferenceExp rexp = (ReferenceExp) context; 100 if ("*".equals(rexp.getName())) 101 return GetNamedInstancePart.makeExp(args[1]); 102 decl = rexp.getBinding(); 103 } 104 105 String mname = ((QuoteExp) args[1]).getValue().toString(); 106 Type type = context.getType(); 107 boolean isInstanceOperator = context == QuoteExp.nullExp; 108 Compilation comp = walker.getCompilation(); 109 Language language = comp.getLanguage(); 110 Type typeval = language.getTypeFor(context, false); 111 ClassType caller = comp == null ? null 112 : comp.curClass != null ? comp.curClass 113 : comp.mainClass; 114 GetNamedExp nexp = (GetNamedExp) exp; 115 116 if (typeval instanceof Type) 117 { 118 if (mname.equals(CLASSTYPE_FOR)) 119 return new QuoteExp(typeval); 120 121 if (typeval instanceof ObjectType) 122 { 123 if (mname.equals("new")) 124 return nexp.setProcedureKind('N'); 125 if (mname.equals(INSTANCEOF_METHOD_NAME)) 126 return nexp.setProcedureKind('I'); 127 if (mname.equals(CAST_METHOD_NAME)) 128 return nexp.setProcedureKind('C'); 129 } 130 } 131 if (typeval instanceof ClassType) 132 { 133 if (mname.length() > 1 && mname.charAt(0) == '.') 134 { 135 return new QuoteExp(new NamedPart(typeval, mname, 'D')); 139 } 140 if (Invoke.checkKnownClass(typeval, comp) < 0) 141 return exp; 142 PrimProcedure[] methods 143 = ClassMethods.getMethods((ClassType) typeval, 144 Compilation.mangleName(mname), 145 '\0', caller, language); 146 if (methods != null && methods.length > 0) 147 { 148 nexp.methods = methods; 149 return nexp.setProcedureKind('S'); 150 } 151 ApplyExp aexp = new ApplyExp(SlotGet.staticField, args); 152 aexp.setLine(exp); 153 return ((InlineCalls) walker).walkApplyOnly(aexp); 154 155 } 156 if (typeval != null) 157 { 158 159 } 160 161 167 168 if (type.isSubtype(Compilation.typeClassType) 169 || type.isSubtype(Type.java_lang_Class_type)) 170 return exp; 174 175 if (type instanceof ObjectType) 176 { 177 ClassType ctype 178 = type instanceof ClassType ? (ClassType) type : Type.pointer_type; 179 PrimProcedure[] methods 180 = ClassMethods.getMethods(ctype, Compilation.mangleName(mname), 181 'V', caller, language); 182 if (methods != null && methods.length > 0) 183 { 184 nexp.methods = methods; 185 return nexp.setProcedureKind('M'); 186 } 187 Member part = SlotGet.lookupMember(ctype, mname, caller); 188 if (part != null 189 || (mname.equals("length") && type instanceof ArrayType)) 190 { 191 ApplyExp aexp = new ApplyExp(SlotGet.field, args); 194 aexp.setLine(exp); 195 return ((InlineCalls) walker).walkApplyOnly(aexp); 196 } 197 198 if (type.isSubtype(typeHasNamedParts)) 199 { 200 Object val; 201 if (decl != null 202 && (val = Declaration.followAliases(decl).getConstantValue()) != null) 203 { 204 HasNamedParts value = (HasNamedParts) val; 205 if (value.isConstant(mname)) 206 { 207 val = value.get(mname); 208 return QuoteExp.getInstance(val); 209 } 210 } 211 return new ApplyExp(typeHasNamedParts.getDeclaredMethod("get", 1), 212 args).setLine(exp); 213 } 214 } 215 216 if (comp.getBooleanOption("warn-invoke-unknown-method", ! comp.immediate)) 217 comp.error('w', "no known slot '"+mname+"' in "+type.getName()); 218 return exp; 219 } 220 221 static final ClassType typeHasNamedParts 222 = ClassType.make("gnu.mapping.HasNamedParts"); 223 224 public Object apply2 (Object container, Object part) 225 throws Throwable 226 { 227 if (container instanceof Values) 228 { 229 Object [] values = ((Values) container).getValues(); 230 Values result = new Values(); 231 for (int i = 0; i < values.length; i++) 232 { 233 Values.writeValues(apply2(values[i], part), result); 234 } 235 return result.canonicalize(); 236 } 237 Symbol sym; 238 if (part instanceof Symbol) 239 sym = (Symbol) part; 240 else 241 sym = Namespace.EmptyNamespace.getSymbol(part.toString().intern()); 242 return getNamedPart(container, sym); 243 } 244 245 public static Object getTypePart (Type type, String name) 246 throws Throwable 247 { 248 if (name.equals(CLASSTYPE_FOR)) 249 return type; 250 251 if (type instanceof ObjectType) 252 { 253 if (name.equals(INSTANCEOF_METHOD_NAME)) 254 return new NamedPart(type, name, 'I'); 255 if (name.equals(CAST_METHOD_NAME)) 256 return new NamedPart(type, name, 'C'); 257 if (name.equals("new")) 258 return new NamedPart(type, name, 'N'); 259 if (name.equals(".length") 260 || (name.length() > 1 && name.charAt(0) == '.' 261 && type instanceof ClassType)) 262 return new NamedPart(type, name, 'D'); 263 } 264 265 if (type instanceof ClassType) 266 { 267 try 268 { 269 return gnu.kawa.reflect.SlotGet.staticField(type, name); 270 } 271 catch (Throwable ex) 272 { 273 } 275 return ClassMethods.apply(ClassMethods.classMethods, type, name); 276 } 277 return getMemberPart(type, name); 278 } 279 280 public static Object getNamedPart (Object container, Symbol part) 281 throws Throwable 282 { 283 String name = part.getName(); 284 if (container instanceof HasNamedParts) 285 return ((HasNamedParts) container).get(name); 286 if (container instanceof Class ) 287 container = (ClassType) Type.make((Class ) container); 288 if (container instanceof Type) 289 return getTypePart((Type) container, name); 290 return getMemberPart(container, part.toString()); 291 } 292 293 public static Object getMemberPart(Object container, String name) 294 throws Throwable 295 { 296 try 297 { 298 return gnu.kawa.reflect.SlotGet.field(container, name); 299 } 300 catch (Throwable ex) 301 { 302 } 304 MethodProc methods = ClassMethods.apply((ClassType) ClassType.make(container.getClass()), 305 Compilation.mangleName(name), '\0', 306 Language.getDefaultLanguage()); 307 if (methods != null) 308 return new NamedPart(container, name, 'M', methods); 309 throw new RuntimeException ("no part '"+name+"' in "+container); 310 } 311 312 public Procedure getSetter() 313 { 314 return SetNamedPart.setNamedPart; 315 } 316 } 317 318 class GetNamedExp extends ApplyExp 319 { 320 329 char kind; 330 PrimProcedure[] methods; 331 332 public String combinedName; 333 334 public void apply (CallContext ctx) throws Throwable 335 { 336 if (combinedName != null) 337 { 338 Environment env = ctx.getEnvironment(); 339 Symbol sym = env.getSymbol(combinedName); 340 Object unb = gnu.mapping.Location.UNBOUND; 341 Object property = null; Object value = env.get(sym, property, unb); 343 if (value != unb) 344 { 345 ctx.writeValue(value); 346 return; 347 } 348 } 349 super.apply(ctx); 350 } 351 352 public GetNamedExp(Expression[] args) 353 { 354 super(GetNamedPart.getNamedPart, args); 355 } 356 357 protected GetNamedExp setProcedureKind (char kind) 358 { 359 this.type = Compilation.typeProcedure; 366 this.kind = kind; 367 return this; 368 } 369 370 public Expression inline (ApplyExp exp, InlineCalls walker, Declaration decl) 371 { 372 Expression[] pargs = getArgs(); 373 Expression context = pargs[0]; 374 Expression[] args = exp.getArgs(); 375 Expression[] xargs; 376 switch (kind) 377 { 378 case 'M': 379 decl = invokeDecl; 380 xargs = new Expression[args.length+2]; 381 xargs[0] = pargs[0]; 382 xargs[1] = pargs[1]; 383 System.arraycopy(args, 0, xargs, 2, args.length); 384 break; 385 case 'N': decl = makeDecl; 387 xargs = new Expression[args.length+1]; 388 System.arraycopy(args, 0, xargs, 1, args.length); 389 xargs[0] = context; 390 break; 391 case 'I': decl = instanceOfDecl; 393 xargs = new Expression[args.length+1]; 394 System.arraycopy(args, 1, xargs, 2, args.length-1); 395 xargs[0] = args[0]; 396 xargs[1] = context; 397 break; 398 case 'C': decl = castDecl; 400 xargs = new Expression[args.length+1]; 401 System.arraycopy(args, 1, xargs, 2, args.length-1); 402 xargs[0] = context; 403 xargs[1] = args[0]; 404 break; 405 case 'S': decl = invokeStaticDecl; 407 xargs = new Expression[args.length+2]; 408 xargs[0] = context; 409 xargs[1] = pargs[1]; 410 System.arraycopy(args, 0, xargs, 2, args.length); 411 break; 412 default: 413 return exp; 414 } 415 ApplyExp result = new ApplyExp(new ReferenceExp(decl), xargs); 416 result.setLine(exp); 417 return walker.walkApplyOnly(result); 418 } 419 420 public boolean side_effects () 421 { 422 if (kind == 'S' || kind == 'N' || kind == 'C' || kind == 'I') 425 return false; 426 if (kind == 'M') 427 return getArgs()[0].side_effects(); 428 return true; 429 } 430 431 static final Declaration fieldDecl 432 = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.SlotGet", "field"); 433 434 static final Declaration staticFieldDecl 435 = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.SlotGet", "staticField"); 436 437 static final Declaration makeDecl 438 = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "make"); 439 440 static final Declaration invokeDecl 441 = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "invoke"); 442 443 static final Declaration invokeStaticDecl 444 = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "invokeStatic"); 445 446 static final Declaration instanceOfDecl 447 = Declaration.getDeclarationFromStatic("kawa.standard.Scheme", "instanceOf"); 448 449 static final Declaration castDecl 450 = Declaration.getDeclarationFromStatic("gnu.kawa.functions.Convert", "as"); 451 } 452 453 class NamedPart extends ProcedureN 454 implements HasSetter, Externalizable, CanInline 455 { 456 Object container; 457 Object member; 458 char kind; 459 MethodProc methods; 460 461 public NamedPart(Object container, Object member, char kind) 462 { 463 this.container = container; 464 this.member = member; 465 this.kind = kind; 466 } 467 468 public NamedPart (Object container, String mname, char kind, 469 MethodProc methods) 470 { 471 this.container = container; 472 this.methods = methods; 473 this.member = mname; 474 this.kind = kind; 475 } 476 477 public int numArgs() 478 { 479 if (kind == 'I' || kind == 'C') 480 return 0x1001; 481 if (kind == 'D') 482 return 0x1000; 483 return 0xfffff000; 484 } 485 486 public Expression inline (ApplyExp exp, ExpWalker walker) 487 { 488 Expression[] args = exp.getArgs(); 489 switch (kind) 490 { 491 case 'D': 492 String fname = member.toString().substring(1); 493 Expression[] xargs = new Expression[2]; 494 xargs[1] = QuoteExp.getInstance(fname); 495 SlotGet proc; 496 if (args.length > 0) 497 { 498 xargs[0] = Convert.makeCoercion(args[0], new QuoteExp(container)); 499 proc = SlotGet.field; 500 } 501 else 502 { 503 xargs[0] = QuoteExp.getInstance(container); 504 proc = SlotGet.staticField; 505 } 506 ApplyExp aexp = new ApplyExp(proc, xargs); 507 aexp.setLine(exp); 508 return ((InlineCalls) walker).walkApplyOnly(aexp); 509 } 510 return exp; 511 } 512 513 public void apply (CallContext ctx) throws Throwable 514 { 515 apply(ctx.getArgs(), ctx); 516 } 517 518 public void apply (Object [] args, CallContext ctx) throws Throwable 519 { 520 if (kind == 'S') 523 methods.checkN(args, ctx); 524 else if (kind=='M') 525 { 526 int nargs = args.length; 527 Object [] xargs = new Object [nargs+1]; 528 xargs[0] = container; 529 System.arraycopy(args, 0, xargs, 1, nargs); 530 methods.checkN(xargs, ctx); 531 } 532 else 533 ctx.writeValue(this.applyN(args)); 534 } 535 536 public Object applyN (Object [] args) 537 throws Throwable 538 { 539 Object [] xargs; 540 541 switch (kind) 542 { 543 case 'I': 544 return kawa.standard.Scheme.instanceOf.apply2(args[0], container); 545 case 'C': 546 return gnu.kawa.functions.Convert.as.apply2(container, args[0]); 547 case 'N': 548 xargs = new Object [args.length+1]; 549 xargs[0] = container; 550 System.arraycopy(args, 0, xargs, 1, args.length); 551 return Invoke.make.applyN(xargs); 552 case 'S': 553 return methods.applyN(args); 554 case 'M': 555 xargs = new Object [args.length+1]; 556 xargs[0] = container; 557 System.arraycopy(args, 0, xargs, 1, args.length); 558 return methods.applyN(xargs); 559 case 'D': 560 String fname = member.toString().substring(1); 561 if (args.length == 0) 562 return SlotGet.staticField((ClassType) container, fname); 563 else 564 return SlotGet.field(((Type) container).coerceFromObject(args[0]), fname); 565 } 566 throw new Error ("unknown part "+member+" in "+container); 567 } 568 569 public Procedure getSetter() 570 { 571 if (kind == 'D') 572 return new NamedPartSetter(this); 573 else 574 throw new RuntimeException ("procedure '"+getName()+ "' has no setter"); 575 } 576 577 public void set0 (Object value) throws Throwable 578 { 579 switch (kind) 580 { 581 case 'D': 582 String fname = member.toString().substring(1); 583 SlotSet.setStaticField((ClassType) container, fname, value); 584 return; 585 default: 586 throw new Error ("invalid setter for "+this); 587 } 588 } 589 590 public void set1 (Object object, Object value) throws Throwable 591 { 592 switch (kind) 593 { 594 case 'D': 595 String fname = member.toString().substring(1); 596 object = ((Type) container).coerceFromObject(object); 597 SlotSet.setField(object, fname, value); 598 return; 599 default: 600 throw new Error ("invalid setter for "+this); 601 } 602 } 603 604 public void writeExternal(ObjectOutput out) throws IOException 605 { 606 out.writeObject(container); 607 out.writeObject(member); 608 out.writeChar(kind); 609 } 610 611 public void readExternal(ObjectInput in) 612 throws IOException, ClassNotFoundException 613 { 614 kind = in.readChar(); 615 container = (Procedure) in.readObject(); 616 member = (Procedure) in.readObject(); 617 } 618 } 619 620 class NamedPartSetter extends gnu.mapping.Setter 621 implements Externalizable, CanInline 622 { 623 public NamedPartSetter (NamedPart getter) 624 { 625 super(getter); 626 } 627 628 public int numArgs() 629 { 630 if (((NamedPart) getter).kind == 'D') 631 return 0x2001; 632 return 0xfffff000; 633 } 634 635 public Expression inline (ApplyExp exp, ExpWalker walker) 636 { 637 NamedPart get = (NamedPart) this.getter; 638 if (get.kind == 'D') 639 { 640 Expression[] xargs = new Expression[3]; 641 xargs[1] = QuoteExp.getInstance(get.member.toString().substring(1)); 642 xargs[2] = exp.getArgs()[0]; 643 SlotSet proc; 644 if (exp.getArgCount() == 1) 645 { 646 xargs[0] = QuoteExp.getInstance(get.container); 647 proc = SlotSet.set$Mnstatic$Mnfield$Ex; 648 } 649 else if (exp.getArgCount() == 2) 650 { 651 xargs[0] 652 = Convert.makeCoercion(exp.getArgs()[0], new QuoteExp(get.container)); 653 proc = SlotSet.set$Mnfield$Ex; 654 } 655 else 656 return exp; 657 ApplyExp aexp = new ApplyExp(proc, xargs); 658 aexp.setLine(exp); 659 return ((InlineCalls) walker).walkApplyOnly(aexp); 660 } 661 return exp; 662 } 663 664 public void writeExternal(ObjectOutput out) throws IOException 665 { 666 out.writeObject(getter); 667 } 668 669 public void readExternal(ObjectInput in) 670 throws IOException, ClassNotFoundException 671 { 672 getter = (Procedure) in.readObject(); 673 } 674 } 675 | Popular Tags |