001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004: import gnu.mapping.*;
005: import java.util.Vector;
006:
007: public class ClassExp extends LambdaExp {
008: boolean simple;
009:
010: public boolean isSimple() {
011: return simple;
012: }
013:
014: public void setSimple(boolean value) {
015: simple = value;
016: }
017:
018: /** True if there is at least one explicit "<init>" ("*init*"} method. */
019: boolean explicitInit;
020:
021: /** The class of instances of this class.
022: * Same as super.type unless isMakingClassPair(), in which case super.type
023: * is an interface, and instanceType is a class implementing the interface.
024: * Using an interface plus a class gives us true multiple inheritance. */
025: ClassType instanceType;
026:
027: /** True if we should make a pair of an interface and a class. */
028: public boolean isMakingClassPair() {
029: return !simple;
030: }
031:
032: /** List of base classes and implemented interfaces. */
033: public Expression[] super s;
034:
035: /** An artificial method named {@code "$finit$"} for evaluating
036: * non-static initializations.
037: * All constructors need to call this. */
038: public LambdaExp initMethod;
039:
040: /** An artificial method named {@code "$clinit$"} for evaluating
041: * static initializations. */
042: public LambdaExp clinitMethod;
043:
044: public ClassExp() {
045: type = null;
046: // Make sure we actually generate a class.
047: setCanRead(true);
048: }
049:
050: public ClassExp(boolean simple) {
051: this .simple = simple;
052: if (simple)
053: instanceType = type = new ClassType();
054: else {
055: PairClassType ptype = new PairClassType();
056: type = ptype;
057: instanceType = new ClassType();
058: ptype.setInterface(true);
059: ptype.instanceType = instanceType;
060: }
061: setCanRead(true);
062: }
063:
064: protected boolean mustCompile() {
065: return true;
066: }
067:
068: public void compile(Compilation comp, Target target) {
069: if (target instanceof IgnoreTarget)
070: return;
071: compile(comp);
072: compilePushClass(comp, target);
073: }
074:
075: public void compilePushClass(Compilation comp, Target target) {
076: ClassType new_class = type;
077: // Type.make(Class.forname)
078:
079: gnu.bytecode.CodeAttr code = comp.getCode();
080: comp.loadClassRef(new_class);
081: ClassType typeType;
082: int nargs;
083: boolean needsLink = getNeedsClosureEnv();
084: if (isMakingClassPair() || needsLink) {
085: if (new_class == instanceType)
086: code.emitDup(instanceType);
087: else
088: comp.loadClassRef(instanceType);
089: typeType = ClassType.make("gnu.expr.PairClassType");
090: nargs = needsLink ? 3 : 2;
091: } else {
092: typeType = ClassType.make("gnu.bytecode.Type");
093: nargs = 1;
094: }
095: Type[] argsClass = new Type[nargs];
096: if (needsLink) {
097: getOwningLambda().loadHeapFrame(comp);
098: argsClass[--nargs] = Type.pointer_type;
099: }
100: ClassType typeClass = ClassType.make("java.lang.Class");
101: while (--nargs >= 0)
102: argsClass[nargs] = typeClass;
103: Method makeMethod = typeType.addMethod("make", argsClass,
104: typeType, Access.STATIC | Access.PUBLIC);
105: code.emitInvokeStatic(makeMethod);
106:
107: target.compileFromStack(comp, typeType);
108: }
109:
110: public String getJavaName() {
111: String name = getName();
112: return name == null ? "object" : Compilation
113: .mangleNameIfNeeded(name);
114: }
115:
116: protected ClassType getCompiledClassType(Compilation comp) {
117: return type;
118: }
119:
120: public void setClassName(Compilation comp) {
121: if (type.getName() == null) {
122: String name = getName();
123: if (name != null) {
124: int nlen = name.length();
125: if (nlen > 2 && name.charAt(0) == '<'
126: && name.charAt(nlen - 1) == '>')
127: name = name.substring(1, nlen - 1);
128: }
129: if (name == null) {
130: StringBuffer nbuf = new StringBuffer(100);
131: comp.getModule().classFor(comp);
132: nbuf.append(comp.mainClass.getName());
133: nbuf.append('$');
134: int len = nbuf.length();
135: for (int i = 0;; i++) {
136: nbuf.append(i);
137: name = nbuf.toString();
138: if (comp.findNamedClass(name) == null)
139: break;
140: nbuf.setLength(len);
141: }
142: } else if (!isSimple() || this instanceof ObjectExp)
143: name = comp.generateClassName(name);
144: else {
145: int start = 0;
146: StringBuffer nbuf = new StringBuffer(100);
147: for (;;) {
148: int dot = name.indexOf('.', start);
149: if (dot < 0)
150: break;
151: nbuf.append(Compilation.mangleNameIfNeeded(name
152: .substring(start, dot)));
153: nbuf.append('.');
154: start = dot + 1;
155: }
156: if (start == 0) {
157: String mainName = comp.mainClass == null ? null
158: : comp.mainClass.getName();
159: int dot = mainName == null ? -1 : mainName
160: .lastIndexOf('.');
161: if (dot > 0)
162: nbuf.append(mainName.substring(0, dot + 1));
163: else if (comp.classPrefix != null)
164: nbuf.append(comp.classPrefix);
165: }
166: if (start < name.length())
167: nbuf.append(Compilation.mangleNameIfNeeded(name
168: .substring(start)));
169: name = nbuf.toString();
170: }
171: type.setName(name);
172: comp.addClass(type);
173: if (isMakingClassPair()) {
174: instanceType.setName(type.getName() + "$class");
175: comp.addClass(instanceType);
176: }
177: }
178: }
179:
180: public void setTypes(Compilation comp) {
181: int len = super s == null ? 0 : super s.length;
182: ClassType[] super Types = new ClassType[len];
183: ClassType super Type = null;
184: int j = 0;
185: for (int i = 0; i < len; i++) {
186: // setTypes may be called at name-resolution time (so we can can
187: // resolve against inherited field and method names). Therefore do
188: // inlining now. Needed (for example) for deprecated PREXIX:<> syntax.
189: super s[i] = new InlineCalls(comp).walk(super s[i]);
190:
191: Type st = Language.getDefaultLanguage().getTypeFor(
192: super s[i]);
193: if (!(st instanceof ClassType)) {
194: comp.setLine(super s[i]);
195: comp.error('e', "invalid super type");
196: continue;
197: }
198: ClassType t = (ClassType) st;
199: int modifiers;
200: try {
201: modifiers = t.getModifiers();
202: } catch (RuntimeException ex) {
203: modifiers = 0;
204: if (comp != null)
205: comp
206: .error('e', "unknown super-type "
207: + t.getName());
208: }
209: if ((modifiers & Access.INTERFACE) == 0) {
210: if (j < i)
211: comp.error('e', "duplicate superclass for " + this );
212: super Type = t;
213: } else
214: super Types[j++] = t;
215: }
216: if (!isSimple()) {
217: if (super Type != null)
218: comp.error('e',
219: "non-simple class inherts from non-interface "
220: + super Type.getName());
221:
222: ClassType[] interfaces = { type };
223: // Can we better. FIXME.
224: instanceType.setSuper(Type.pointer_type);
225: instanceType.setInterfaces(interfaces);
226: }
227: type
228: .setSuper(super Type == null ? Type.pointer_type
229: : super Type);
230:
231: ClassType[] interfaces;
232: if (j == len)
233: interfaces = super Types;
234: else {
235: interfaces = new ClassType[j];
236: System.arraycopy(super Types, 0, interfaces, 0, j);
237: }
238: type.setInterfaces(interfaces);
239: }
240:
241: boolean partsDeclared;
242:
243: public void declareParts(Compilation comp) {
244: if (partsDeclared)
245: return;
246: partsDeclared = true;
247: for (Declaration decl = firstDecl(); decl != null; decl = decl
248: .nextDecl()) {
249: // If the declaration derives from a method, don't create field.
250: if (decl.getCanRead()) {
251: int flags = decl.getAccessFlags(Access.PUBLIC);
252: if (decl.getFlag(Declaration.STATIC_SPECIFIED))
253: flags |= Access.STATIC;
254: if (isMakingClassPair()) {
255: flags |= Access.ABSTRACT;
256: Type ftype = decl.getType().getImplementationType();
257: type.addMethod(slotToMethodName("get", decl
258: .getName()), flags, Type.typeArray0, ftype);
259: Type[] stypes = { ftype };
260: type.addMethod(slotToMethodName("set", decl
261: .getName()), flags, stypes, Type.void_type);
262: } else {
263: String fname = Compilation.mangleNameIfNeeded(decl
264: .getName());
265: decl.field = instanceType.addField(fname, decl
266: .getType(), flags);
267: decl.setSimple(false);
268: }
269: }
270: }
271:
272: for (LambdaExp child = firstChild; child != null; child = child.nextSibling) {
273: if ("*init*".equals(child.getName()))
274: explicitInit = true;
275: if ((child != initMethod && child != clinitMethod)
276: || !isMakingClassPair())
277: child.addMethodFor(type, comp, null);
278: if (isMakingClassPair())
279: // FIXME this is wrong if the method is static
280: child.addMethodFor(instanceType, comp, type);
281: }
282: if (!explicitInit)
283: Compilation.getConstructor(instanceType, this );
284: }
285:
286: /** Return implementation method matching name and param types.
287: * Used when compiling a pair class and generating a concrete method
288: * implementing an interface method, to find static implementation method
289: * in this or super implementation class we need to call.
290: * @param interfaceType search the implementation classes corresponding
291: * to this interface type and its super-interfaces.
292: * @param mname method name to look for.
293: * @param paramTypes method types to look for.
294: * @param vec where to place found methods
295: * If a method is found, don't search super-interfaces, as the found method
296: * is more specific and overrides any that might in super-interfaces.
297: */
298: static void getImplMethods(ClassType interfaceType, String mname,
299: Type[] paramTypes, Vector vec) {
300: ClassType implType;
301: if (interfaceType instanceof PairClassType)
302: implType = ((PairClassType) interfaceType).instanceType;
303: else if (!interfaceType.isInterface())
304: return;
305: else {
306: String implTypeName = interfaceType.getName() + "$class";
307: implType = ClassType.make(implTypeName);
308: }
309: Type[] itypes = new Type[paramTypes.length + 1];
310: itypes[0] = interfaceType;
311: System.arraycopy(paramTypes, 0, itypes, 1, paramTypes.length);
312: Method implMethod = implType.getDeclaredMethod(mname, itypes);
313: if (implMethod != null) {
314: int count = vec.size();
315: if (count == 0
316: || !vec.elementAt(count - 1).equals(implMethod))
317: vec.addElement(implMethod);
318: } else {
319: ClassType[] super Interfaces = interfaceType.getInterfaces();
320: for (int i = 0; i < super Interfaces.length; i++)
321: getImplMethods(super Interfaces[i], mname, paramTypes,
322: vec);
323: }
324: }
325:
326: /** Call comp.usedClass on the first arguments's supertypes. */
327: private static void usedSuperClasses(ClassType clas,
328: Compilation comp) {
329: comp.usedClass(clas.getSuperclass());
330: ClassType[] interfaces = clas.getInterfaces();
331: if (interfaces != null) {
332: for (int i = interfaces.length; --i >= 0;)
333: comp.usedClass(interfaces[i]);
334: }
335: }
336:
337: public ClassType compile(Compilation comp) {
338: ClassType saveClass = comp.curClass;
339: Method saveMethod = comp.method;
340: try {
341: ClassType new_class = getCompiledClassType(comp);
342: comp.curClass = new_class;
343:
344: usedSuperClasses(type, comp);
345: if (type != instanceType)
346: usedSuperClasses(instanceType, comp);
347:
348: String filename = getFileName();
349: if (filename != null)
350: new_class.setSourceFile(filename);
351:
352: LambdaExp saveLambda = comp.curLambda;
353: comp.curLambda = this ;
354:
355: allocFrame(comp);
356: CodeAttr code;
357:
358: for (LambdaExp child = firstChild; child != null;) {
359: Method save_method = comp.method;
360: LambdaExp save_lambda = comp.curLambda;
361: String saveFilename = comp.getFileName();
362: int saveLine = comp.getLineNumber();
363: int saveColumn = comp.getColumnNumber();
364: comp.setLine(child);
365: comp.method = child.getMainMethod();
366: //comp.curClass = comp.method.getDeclaringClass();
367: Declaration childDecl = child.nameDecl;
368: if (childDecl == null
369: || !childDecl
370: .getFlag(Declaration.STATIC_SPECIFIED))
371: child.declareThis(comp.curClass);
372: comp.curClass = instanceType;
373: comp.curLambda = child;
374: comp.method.initCode();
375: child.allocChildClasses(comp);
376: child.allocParameters(comp);
377: child.enterFunction(comp);
378: if ("*init*".equals(child.getName())) {
379: code = comp.getCode();
380:
381: // Extract "first" expression to see if it is special.
382: Expression bodyFirst = child.body;
383: while (bodyFirst instanceof BeginExp) {
384: BeginExp bbody = (BeginExp) bodyFirst;
385: if (bbody.length == 0)
386: bodyFirst = null;
387: else
388: bodyFirst = bbody.exps[0];
389: }
390:
391: // See if bodyFirst is a this(...) or super(...) call.
392: ClassType calledInit = null;
393: Object value;
394: Expression exp;
395: if (bodyFirst instanceof ApplyExp
396: && (exp = ((ApplyExp) bodyFirst).func) instanceof QuoteExp
397: && (value = ((QuoteExp) exp).getValue()) instanceof PrimProcedure) {
398: PrimProcedure pproc = (PrimProcedure) value;
399: if (pproc.isSpecial()
400: && ("<init>".equals(pproc.method
401: .getName())))
402: calledInit = pproc.method
403: .getDeclaringClass();
404: }
405: ClassType super Class = instanceType.getSuperclass();
406: if (calledInit != null) {
407: bodyFirst.compileWithPosition(comp,
408: Target.Ignore);
409: if (calledInit != instanceType
410: && calledInit != super Class)
411: comp
412: .error('e',
413: "call to <init> for not this or super class");
414: } else if (calledInit != super Class) {
415: // Call default super constructor if there isn't an explicit
416: // call to a super constructor.
417: Method super Constructor = super Class
418: .getDeclaredMethod("<init>", 0);
419: if (super Constructor == null)
420: comp
421: .error('e',
422: "super class does not have a default constructor");
423: else {
424: code.emitPushThis();
425: code.emitInvokeSpecial(super Constructor);
426: }
427: }
428: if (calledInit != instanceType)
429: comp.callInitMethods(
430: getCompiledClassType(comp), new Vector(
431: 10));
432: if (calledInit != null)
433: // Skip bodyFirst since we already compiled it.
434: Expression.compileButFirst(child.body, comp);
435: else
436: child.compileBody(comp);
437: } else
438: child.compileBody(comp);
439: child.compileEnd(comp);
440: child.compileChildMethods(comp);
441: comp.method = save_method;
442: comp.curClass = new_class;
443: comp.curLambda = save_lambda;
444: comp.setLine(saveFilename, saveLine, saveColumn);
445: child = child.nextSibling;
446: }
447: if (!explicitInit)
448: comp.generateConstructor(instanceType, this );
449: else if (initChain != null)
450: initChain
451: .reportError(
452: "unimplemented: explicit constructor cannot initialize ",
453: comp);
454:
455: Method[] methods = type.getMethods(
456: AbstractMethodFilter.instance, 2);
457: for (int i = 0; i < methods.length; i++) {
458: Method meth = methods[i];
459: String mname = meth.getName();
460: Type[] ptypes = meth.getParameterTypes();
461: Type rtype = meth.getReturnType();
462:
463: Method mimpl = instanceType.getMethod(mname, ptypes);
464: if (mimpl != null && !mimpl.isAbstract())
465: continue;
466:
467: char ch;
468: if (mname.length() > 3 && mname.charAt(2) == 't'
469: && mname.charAt(1) == 'e'
470: && ((ch = mname.charAt(0)) == 'g' || ch == 's')) { // a "set" or "get" method is treated as a slot accessor.
471: Type ftype;
472: if (ch == 's' && rtype.isVoid()
473: && ptypes.length == 1)
474: ftype = ptypes[0];
475: else if (ch == 'g' && ptypes.length == 0)
476: ftype = rtype;
477: else
478: continue;
479: String fname = Character.toLowerCase(mname
480: .charAt(3))
481: + mname.substring(4);
482: Field fld = instanceType.getField(fname);
483: if (fld == null)
484: fld = instanceType.addField(fname, ftype,
485: Access.PUBLIC);
486: Method impl = instanceType.addMethod(mname,
487: Access.PUBLIC, ptypes, rtype);
488: code = impl.startCode();
489: code.emitPushThis();
490: if (ch == 'g') {
491: code.emitGetField(fld);
492: } else {
493: code.emitLoad(code.getArg(1));
494: code.emitPutField(fld);
495: }
496: code.emitReturn();
497: } else {
498: Vector vec = new Vector();
499: getImplMethods(type, mname, ptypes, vec);
500: if (vec.size() != 1) {
501: // FIXME - need better error message!
502: String msg = vec.size() == 0 ? "missing implementation for "
503: : "ambiguous implementation for ";
504: comp.error('e', msg + meth + " mname:" + mname);
505: } else {
506: Method impl = instanceType.addMethod(mname,
507: Access.PUBLIC, ptypes, rtype);
508: code = impl.startCode();
509: for (Variable var = code.getCurrentScope()
510: .firstVar(); var != null; var = var
511: .nextVar())
512: code.emitLoad(var);
513: Method imethod = (Method) vec.elementAt(0);
514: code.emitInvokeStatic(imethod);
515: code.emitReturn();
516: }
517: }
518: }
519:
520: generateApplyMethods(comp);
521: comp.curLambda = saveLambda;
522:
523: return new_class;
524: } finally {
525: comp.curClass = saveClass;
526: comp.method = saveMethod;
527: }
528: }
529:
530: protected Expression walk(ExpWalker walker) {
531: Compilation comp = walker.getCompilation();
532: if (comp == null)
533: return walker.walkClassExp(this );
534: ClassType saveClass = comp.curClass;
535: try {
536: comp.curClass = type;
537: return walker.walkClassExp(this );
538: } finally {
539: comp.curClass = saveClass;
540: }
541: }
542:
543: protected void walkChildren(ExpWalker walker) {
544: LambdaExp save = walker.currentLambda;
545: walker.currentLambda = this ;
546: try {
547: for (LambdaExp child = firstChild; child != null
548: && walker.exitValue == null; child = child.nextSibling) {
549: if (instanceType != null) {
550: Declaration firstParam = child.firstDecl();
551: if (firstParam != null
552: && firstParam.isThisParameter())
553: firstParam.setType(type);
554: }
555: walker.walkLambdaExp(child);
556: }
557: } finally {
558: walker.currentLambda = save;
559: }
560: }
561:
562: public void print(OutPort out) {
563: out.startLogicalBlock("(" + getExpClassName() + "/", ")", 2);
564: Object name = getSymbol();
565: if (name != null) {
566: out.print(name);
567: out.print('/');
568: }
569: out.print(id);
570: out.print("/fl:");
571: out.print(Integer.toHexString(flags));
572: out.print(" (");
573: Special prevMode = null;
574: int i = 0;
575: int key_args = keywords == null ? 0 : keywords.length;
576: //int opt_args = defaultArgs == null ? 0 : defaultArgs.length - key_args;
577: for (Declaration decl = firstDecl(); decl != null; decl = decl
578: .nextDecl()) {
579: if (i > 0)
580: out.print(' ');
581: decl.printInfo(out);
582: i++;
583: }
584: out.print(") ");
585: for (LambdaExp child = firstChild; child != null; child = child.nextSibling) {
586: out.writeBreakLinear();
587: child.print(out);
588: }
589: if (body != null) {
590: out.writeBreakLinear();
591: body.print(out);
592: }
593: out.endLogicalBlock(")");
594: }
595:
596: public Field compileSetField(Compilation comp) {
597: return (new ClassInitializer(this , comp)).field;
598: }
599:
600: /** Mangle a "slot" name to a get- or set- method name.
601: * @param prefix either "get" or "set"
602: * @param sname a "slot" (property) name. This is mangled if needed.
603: */
604: public static String slotToMethodName(String prefix, String sname) {
605: if (!Compilation.isValidJavaName(sname))
606: sname = Compilation.mangleName(sname, false);
607: StringBuffer sbuf = new StringBuffer(sname.length() + 3);
608: sbuf.append(prefix);
609: sbuf.append(Character.toTitleCase(sname.charAt(0)));
610: sbuf.append(sname.substring(1));
611: return sbuf.toString();
612: }
613:
614: /** Helper class uses by ClassExp.compile.
615: */
616: private static class AbstractMethodFilter implements
617: gnu.bytecode.Filter {
618: public static final AbstractMethodFilter instance = new AbstractMethodFilter();
619:
620: public boolean select(Object value) {
621: gnu.bytecode.Method method = (gnu.bytecode.Method) value;
622: return method.isAbstract();
623: }
624: }
625: }
|