1 package gnu.expr; 2 import gnu.bytecode.*; 3 import gnu.mapping.*; 4 import java.util.Vector ; 5 6 public class ClassExp extends LambdaExp 7 { 8 boolean simple; 9 public boolean isSimple() { return simple; } 10 public void setSimple(boolean value) { simple = value; } 11 12 13 boolean explicitInit; 14 15 19 ClassType instanceType; 20 21 22 public boolean isMakingClassPair() 23 { 24 return ! simple; 25 } 26 27 28 public Expression[] supers; 29 30 33 public LambdaExp initMethod; 34 35 37 public LambdaExp clinitMethod; 38 39 public ClassExp () 40 { 41 type = null; 42 setCanRead(true); 44 } 45 46 public ClassExp (boolean simple) 47 { 48 this.simple = simple; 49 if (simple) 50 instanceType = type = new ClassType(); 51 else 52 { 53 PairClassType ptype = new PairClassType(); 54 type = ptype; 55 instanceType = new ClassType(); 56 ptype.setInterface(true); 57 ptype.instanceType = instanceType; 58 } 59 setCanRead(true); 60 } 61 62 protected boolean mustCompile () { return true; } 63 64 public void compile (Compilation comp, Target target) 65 { 66 if (target instanceof IgnoreTarget) 67 return; 68 compile (comp); 69 compilePushClass(comp, target); 70 } 71 72 public void compilePushClass (Compilation comp, Target target) 73 { 74 ClassType new_class = type; 75 77 gnu.bytecode.CodeAttr code = comp.getCode(); 78 comp.loadClassRef(new_class); 79 ClassType typeType; 80 int nargs; 81 boolean needsLink = getNeedsClosureEnv(); 82 if (isMakingClassPair() || needsLink) 83 { 84 if (new_class == instanceType) 85 code.emitDup(instanceType); 86 else 87 comp.loadClassRef(instanceType); 88 typeType = ClassType.make("gnu.expr.PairClassType"); 89 nargs = needsLink ? 3 : 2; 90 } 91 else 92 { 93 typeType = ClassType.make("gnu.bytecode.Type"); 94 nargs = 1; 95 } 96 Type[] argsClass = new Type[nargs]; 97 if (needsLink) 98 { 99 getOwningLambda().loadHeapFrame(comp); 100 argsClass[--nargs] = Type.pointer_type; 101 } 102 ClassType typeClass = ClassType.make("java.lang.Class"); 103 while (--nargs >= 0) argsClass[nargs] = typeClass; 104 Method makeMethod 105 = typeType.addMethod("make", argsClass, 106 typeType, Access.STATIC|Access.PUBLIC); 107 code.emitInvokeStatic(makeMethod); 108 109 target.compileFromStack(comp, typeType); 110 } 111 112 public String getJavaName () 113 { 114 String name = getName(); 115 return name == null ? "object" : Compilation.mangleNameIfNeeded (name); 116 } 117 118 protected ClassType getCompiledClassType(Compilation comp) 119 { 120 return type; 121 } 122 123 public void setClassName (Compilation comp) 124 { 125 if (type.getName() == null) 126 { 127 String name = getName(); 128 if (name != null) 129 { 130 int nlen = name.length(); 131 if (nlen > 2 132 && name.charAt(0) == '<' && name.charAt(nlen-1) == '>') 133 name = name.substring(1, nlen-1); 134 } 135 if (name == null) 136 { 137 StringBuffer nbuf = new StringBuffer (100); 138 comp.getModule().classFor(comp); 139 nbuf.append(comp.mainClass.getName()); 140 nbuf.append('$'); 141 int len = nbuf.length(); 142 for (int i = 0; ; i++) 143 { 144 nbuf.append(i); 145 name = nbuf.toString(); 146 if (comp.findNamedClass(name) == null) 147 break; 148 nbuf.setLength(len); 149 } 150 } 151 else if (! isSimple() || this instanceof ObjectExp) 152 name = comp.generateClassName(name); 153 else 154 { 155 int start = 0; 156 StringBuffer nbuf = new StringBuffer (100); 157 for (;;) 158 { 159 int dot = name.indexOf('.', start); 160 if (dot < 0) 161 break; 162 nbuf.append(Compilation 163 .mangleNameIfNeeded(name.substring(start, dot))); 164 nbuf.append('.'); 165 start = dot + 1; 166 } 167 if (start == 0) 168 { 169 String mainName = comp.mainClass == null ? null 170 : comp.mainClass.getName(); 171 int dot = mainName == null ? -1 : mainName.lastIndexOf('.'); 172 if (dot > 0) 173 nbuf.append(mainName.substring(0, dot + 1)); 174 else if (comp.classPrefix != null) 175 nbuf.append(comp.classPrefix); 176 } 177 if (start < name.length()) 178 nbuf.append(Compilation 179 .mangleNameIfNeeded(name.substring(start))); 180 name = nbuf.toString(); 181 } 182 type.setName(name); 183 comp.addClass(type); 184 if (isMakingClassPair()) 185 { 186 instanceType.setName(type.getName()+"$class"); 187 comp.addClass(instanceType); 188 } 189 } 190 } 191 192 public void setTypes(Compilation comp) 193 { 194 int len = supers == null ? 0 : supers.length; 195 ClassType[] superTypes = new ClassType[len]; 196 ClassType superType = null; 197 int j = 0; 198 for (int i = 0; i < len; i++) 199 { 200 supers[i] = new InlineCalls(comp).walk(supers[i]); 204 205 Type st = Language.getDefaultLanguage().getTypeFor(supers[i]); 206 if (! (st instanceof ClassType)) 207 { 208 comp.setLine(supers[i]); 209 comp.error('e', "invalid super type"); 210 continue; 211 } 212 ClassType t = (ClassType) st; 213 int modifiers; 214 try 215 { 216 modifiers = t.getModifiers(); 217 } 218 catch (RuntimeException ex) 219 { 220 modifiers = 0; 221 if (comp != null) 222 comp.error('e', "unknown super-type "+t.getName()); 223 } 224 if ((modifiers & Access.INTERFACE) == 0) 225 { 226 if (j < i) 227 comp.error('e', "duplicate superclass for "+this); 228 superType = t; 229 } 230 else 231 superTypes[j++] = t; 232 } 233 if (! isSimple()) 234 { 235 if (superType != null) 236 comp.error('e', "non-simple class inherts from non-interface "+superType.getName()); 237 238 ClassType[] interfaces = { type }; 239 instanceType.setSuper(Type.pointer_type); 241 instanceType.setInterfaces(interfaces); 242 } 243 type.setSuper(superType == null ? Type.pointer_type : superType); 244 245 ClassType[] interfaces; 246 if (j == len) 247 interfaces = superTypes; 248 else 249 { 250 interfaces = new ClassType[j]; 251 System.arraycopy(superTypes, 0, interfaces, 0, j); 252 } 253 type.setInterfaces(interfaces); 254 } 255 256 boolean partsDeclared; 257 258 public void declareParts(Compilation comp) 259 { 260 if (partsDeclared) 261 return; 262 partsDeclared = true; 263 for (Declaration decl = firstDecl(); 264 decl != null; decl = decl.nextDecl()) 265 { 266 if (decl.getCanRead()) 268 { 269 int flags = decl.getAccessFlags(Access.PUBLIC); 270 if (decl.getFlag(Declaration.STATIC_SPECIFIED)) 271 flags |= Access.STATIC; 272 if (isMakingClassPair()) 273 { 274 flags |= Access.ABSTRACT; 275 Type ftype = decl.getType().getImplementationType(); 276 type.addMethod(slotToMethodName("get", decl.getName()), 277 flags, Type.typeArray0, ftype); 278 Type[] stypes = { ftype }; 279 type.addMethod(slotToMethodName("set",decl.getName()), 280 flags, stypes, Type.void_type); 281 } 282 else 283 { 284 String fname 285 = Compilation.mangleNameIfNeeded(decl.getName()); 286 decl.field 287 = instanceType.addField(fname, decl.getType(), flags); 288 decl.setSimple(false); 289 } 290 } 291 } 292 293 for (LambdaExp child = firstChild; child != null; 294 child = child.nextSibling) 295 { 296 if ("*init*".equals(child.getName())) 297 explicitInit = true; 298 if ((child != initMethod && child != clinitMethod) 299 || ! isMakingClassPair()) 300 child.addMethodFor(type, comp, null); 301 if (isMakingClassPair()) 302 child.addMethodFor(instanceType, comp, type); 304 } 305 if (! explicitInit) 306 Compilation.getConstructor(instanceType, this); 307 } 308 309 321 static void getImplMethods(ClassType interfaceType, 322 String mname, Type[] paramTypes, Vector vec) 323 { 324 ClassType implType; 325 if (interfaceType instanceof PairClassType) 326 implType = ((PairClassType) interfaceType).instanceType; 327 else if (! interfaceType.isInterface()) 328 return; 329 else 330 { 331 String implTypeName = interfaceType.getName() + "$class"; 332 implType = ClassType.make(implTypeName); 333 } 334 Type[] itypes = new Type[paramTypes.length + 1]; 335 itypes[0] = interfaceType; 336 System.arraycopy (paramTypes, 0, itypes, 1, paramTypes.length); 337 Method implMethod = implType.getDeclaredMethod(mname, itypes); 338 if (implMethod != null) 339 { 340 int count = vec.size(); 341 if (count == 0 || ! vec.elementAt(count-1).equals(implMethod)) 342 vec.addElement(implMethod); 343 } 344 else 345 { 346 ClassType[] superInterfaces = interfaceType.getInterfaces(); 347 for (int i = 0; i < superInterfaces.length; i++) 348 getImplMethods(superInterfaces[i], mname, paramTypes, vec); 349 } 350 } 351 352 353 private static void usedSuperClasses(ClassType clas, Compilation comp) 354 { 355 comp.usedClass(clas.getSuperclass()); 356 ClassType[] interfaces = clas.getInterfaces(); 357 if (interfaces != null) 358 { 359 for (int i = interfaces.length; --i >= 0; ) 360 comp.usedClass(interfaces[i]); 361 } 362 } 363 364 public ClassType compile (Compilation comp) 365 { 366 ClassType saveClass = comp.curClass; 367 Method saveMethod = comp.method; 368 try 369 { 370 ClassType new_class = getCompiledClassType(comp); 371 comp.curClass = new_class; 372 373 usedSuperClasses(type, comp); 374 if (type != instanceType) 375 usedSuperClasses(instanceType, comp); 376 377 String filename = getFileName(); 378 if (filename != null) 379 new_class.setSourceFile (filename); 380 381 LambdaExp saveLambda = comp.curLambda; 382 comp.curLambda = this; 383 384 allocFrame(comp); 385 if (getNeedsStaticLink()) 386 { 387 Variable parentFrame = saveLambda.heapFrame != null 388 ? saveLambda.heapFrame 389 : saveLambda.closureEnv; 390 if (parentFrame != null) 391 closureEnvField = staticLinkField 392 = instanceType.setOuterLink((ClassType) parentFrame.getType()); 393 } 394 CodeAttr code; 395 396 for (LambdaExp child = firstChild; child != null; ) 397 { 398 Method save_method = comp.method; 399 LambdaExp save_lambda = comp.curLambda; 400 String saveFilename = comp.getFileName(); 401 int saveLine = comp.getLineNumber(); 402 int saveColumn = comp.getColumnNumber(); 403 comp.setLine(child); 404 comp.method = child.getMainMethod(); 405 Declaration childDecl = child.nameDecl; 407 if (childDecl == null 408 || ! childDecl.getFlag(Declaration.STATIC_SPECIFIED)) 409 child.declareThis(comp.curClass); 410 comp.curClass = instanceType; 411 comp.curLambda = child; 412 comp.method.initCode(); 413 child.allocChildClasses(comp); 414 child.allocParameters(comp); 415 child.enterFunction(comp); 416 if ("*init*".equals(child.getName())) 417 { 418 code = comp.getCode(); 419 420 Expression bodyFirst = child.body; 422 while (bodyFirst instanceof BeginExp) 423 { 424 BeginExp bbody = (BeginExp) bodyFirst; 425 if (bbody.length == 0) 426 bodyFirst = null; 427 else 428 bodyFirst = bbody.exps[0]; 429 } 430 431 ClassType calledInit = null; 433 Object value; Expression exp; 434 if (bodyFirst instanceof ApplyExp 435 && (exp = ((ApplyExp) bodyFirst).func) instanceof QuoteExp 436 && (value = ((QuoteExp) exp).getValue()) instanceof PrimProcedure) 437 { 438 PrimProcedure pproc = (PrimProcedure) value; 439 if (pproc.isSpecial() 440 && ("<init>".equals(pproc.method.getName()))) 441 calledInit = pproc.method.getDeclaringClass(); 442 } 443 ClassType superClass = instanceType.getSuperclass(); 444 if (calledInit != null) 445 { 446 bodyFirst.compileWithPosition(comp, Target.Ignore); 447 if (calledInit != instanceType && calledInit != superClass) 448 comp.error('e', "call to <init> for not this or super class"); 449 } 450 else if (calledInit != superClass) 451 { 452 Method superConstructor 455 = superClass.getDeclaredMethod("<init>", 0); 456 if (superConstructor == null) 457 comp.error('e', "super class does not have a default constructor"); 458 else 459 { 460 code.emitPushThis(); 461 code.emitInvokeSpecial(superConstructor); 462 } 463 } 464 if (calledInit != instanceType) 465 comp.callInitMethods(getCompiledClassType(comp), 466 new Vector (10)); 467 if (calledInit != null) 468 Expression.compileButFirst(child.body, comp); 470 else 471 child.compileBody(comp); 472 } 473 else 474 child.compileBody(comp); 475 child.compileEnd(comp); 476 child.compileChildMethods(comp); 477 comp.method = save_method; 478 comp.curClass = new_class; 479 comp.curLambda = save_lambda; 480 comp.setLine(saveFilename, saveLine, saveColumn); 481 child = child.nextSibling; 482 } 483 if (! explicitInit) 484 comp.generateConstructor(instanceType, this); 485 else if (initChain != null) 486 initChain.reportError("unimplemented: explicit constructor cannot initialize ", comp); 487 488 Method[] methods = type.getMethods(AbstractMethodFilter.instance, 2); 489 for (int i = 0; i < methods.length; i++) 490 { 491 Method meth = methods[i]; 492 String mname = meth.getName(); 493 Type[] ptypes = meth.getParameterTypes(); 494 Type rtype = meth.getReturnType(); 495 496 Method mimpl = instanceType.getMethod(mname, ptypes); 497 if (mimpl != null && ! mimpl.isAbstract()) 498 continue; 499 500 char ch; 501 if (mname.length() > 3 502 && mname.charAt(2) == 't' 503 && mname.charAt(1) == 'e' 504 && ((ch = mname.charAt(0)) == 'g' || ch == 's')) 505 { Type ftype; 507 if (ch == 's' && rtype.isVoid() && ptypes.length == 1) 508 ftype = ptypes[0]; 509 else if (ch == 'g' && ptypes.length == 0) 510 ftype = rtype; 511 else 512 continue; 513 String fname = Character.toLowerCase(mname.charAt(3)) 514 + mname.substring(4); 515 Field fld = instanceType.getField(fname); 516 if (fld == null) 517 fld = instanceType.addField(fname, ftype, Access.PUBLIC); 518 Method impl = instanceType.addMethod(mname, Access.PUBLIC, 519 ptypes, rtype); 520 code = impl.startCode(); 521 code.emitPushThis(); 522 if (ch == 'g') 523 { 524 code.emitGetField(fld); 525 } 526 else 527 { 528 code.emitLoad(code.getArg(1)); 529 code.emitPutField(fld); 530 } 531 code.emitReturn(); 532 } 533 else 534 { 535 Vector vec = new Vector (); 536 getImplMethods(type, mname, ptypes, vec); 537 if (vec.size() != 1) 538 { 539 String msg = vec.size() == 0 541 ? "missing implementation for " 542 : "ambiguous implementation for "; 543 comp.error('e', msg+meth+" mname:"+mname); 544 } 545 else 546 { 547 Method impl = instanceType.addMethod(mname, Access.PUBLIC, 548 ptypes, rtype); 549 code = impl.startCode(); 550 for (Variable var = code.getCurrentScope().firstVar(); 551 var != null; var = var.nextVar()) 552 code.emitLoad(var); 553 Method imethod = (Method) vec.elementAt(0); 554 code.emitInvokeStatic(imethod); 555 code.emitReturn(); 556 } 557 } 558 } 559 560 generateApplyMethods(comp); 561 comp.curLambda = saveLambda; 562 563 return new_class; 564 } 565 finally 566 { 567 comp.curClass = saveClass; 568 comp.method = saveMethod; 569 } 570 } 571 572 protected Expression walk (ExpWalker walker) 573 { 574 Compilation comp = walker.getCompilation(); 575 if (comp == null) 576 return walker.walkClassExp(this); 577 ClassType saveClass = comp.curClass; 578 try 579 { 580 comp.curClass = type; 581 return walker.walkClassExp(this); 582 } 583 finally 584 { 585 comp.curClass = saveClass; 586 } 587 } 588 589 protected void walkChildren(ExpWalker walker) 590 { 591 LambdaExp save = walker.currentLambda; 592 walker.currentLambda = this; 593 try 594 { 595 for (LambdaExp child = firstChild; 596 child != null && walker.exitValue == null; 597 child = child.nextSibling) 598 { 599 if (instanceType != null) 600 { 601 Declaration firstParam = child.firstDecl(); 602 if (firstParam != null && firstParam.isThisParameter()) 603 firstParam.setType(type); 604 } 605 walker.walkLambdaExp(child); 606 } 607 } 608 finally 609 { 610 walker.currentLambda = save; 611 } 612 } 613 614 public void print (OutPort out) 615 { 616 out.startLogicalBlock("("+getExpClassName()+"/", ")", 2); 617 Object name = getSymbol(); 618 if (name != null) 619 { 620 out.print(name); 621 out.print('/'); 622 } 623 out.print(id); 624 out.print("/fl:"); out.print(Integer.toHexString(flags)); 625 out.print(" ("); 626 Special prevMode = null; 627 int i = 0; 628 int key_args = keywords == null ? 0 : keywords.length; 629 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 631 { 632 if (i > 0) 633 out.print(' '); 634 decl.printInfo(out); 635 i++; 636 } 637 out.print(") "); 638 for (LambdaExp child = firstChild; child != null; 639 child = child.nextSibling) 640 { 641 out.writeBreakLinear(); 642 child.print(out); 643 } 644 if (body != null) 645 { 646 out.writeBreakLinear(); 647 body.print (out); 648 } 649 out.endLogicalBlock(")"); 650 } 651 652 public Field compileSetField (Compilation comp) 653 { 654 return (new ClassInitializer(this, comp)).field; 655 } 656 657 661 public static String slotToMethodName(String prefix, String sname) 662 { 663 if (! Compilation.isValidJavaName(sname)) 664 sname = Compilation.mangleName(sname, false); 665 StringBuffer sbuf = new StringBuffer (sname.length()+3); 666 sbuf.append(prefix); 667 sbuf.append(Character.toTitleCase(sname.charAt(0))); 668 sbuf.append(sname.substring(1)); 669 return sbuf.toString(); 670 } 671 672 674 private static class AbstractMethodFilter implements gnu.bytecode.Filter 675 { 676 public static final AbstractMethodFilter instance 677 = new AbstractMethodFilter(); 678 679 public boolean select(Object value) 680 { 681 gnu.bytecode.Method method = (gnu.bytecode.Method) value; 682 return method.isAbstract(); 683 } 684 } 685 } 686 | Popular Tags |