001: /*
002: * SubtypeGenerator.java
003: *
004: * Copyright (c) 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package org.pnuts.lang;
010:
011: import java.io.*;
012: import java.lang.reflect.Constructor;
013: import java.lang.reflect.Method;
014: import java.lang.reflect.Modifier;
015: import java.util.ArrayList;
016: import java.util.List;
017: import java.util.Iterator;
018: import java.util.HashSet;
019: import java.util.Set;
020: import java.util.Map;
021: import java.util.HashMap;
022: import java.util.Enumeration;
023: import java.util.Hashtable;
024:
025: import pnuts.compiler.Compiler;
026: import pnuts.compiler.ClassFile;
027: import pnuts.compiler.Constants;
028: import pnuts.compiler.Label;
029: import pnuts.compiler.MultiClassLoader;
030: import pnuts.compiler.Opcode;
031: import pnuts.compiler.ClassGenerator;
032: import pnuts.lang.Context;
033: import pnuts.lang.Function;
034: import pnuts.lang.Package;
035: import pnuts.lang.Pnuts;
036: import pnuts.lang.SimpleNode;
037: import pnuts.lang.PnutsException;
038: import pnuts.lang.PnutsFunction;
039: import pnuts.lang.Runtime;
040:
041: /**
042: * This class provides a way to extends a Java class in Pnuts.
043: */
044: public class SubtypeGenerator extends Runtime {
045:
046: private final static boolean DEBUG = false;
047:
048: public final static int THIS = 0x0001;
049: public final static int SUPER = 0x0002;
050:
051: private final static String SUPER_PROXY_NAME = "pnuts.compiler.ClassGenerator$SuperCallProxy";
052:
053: protected SubtypeGenerator() {
054: }
055:
056: /**
057: * Generates a class that extends the superClass and implements the
058: * interfaces. Functions in the pkg are mapped to non-final/static
059: * public/protected methods with the same name and the same number of
060: * parameters. Note that this method may throw ClassFormatError.
061: *
062: * @param superClass
063: * super class that the generated class extends
064: * @param interfaces
065: * list of interfaces that the generated class implements
066: * @param pkg
067: * a Package that includes functions to be mapped to methods.
068: * @param context
069: * a Context in which functions are extracted from pkg
070: * @param mode
071: * THIS if each function has 'this' parameter, otherwise 0.
072: * @return the generated class
073: */
074: public static Class generateSubclass(Class super Class,
075: Class[] interfaces, Package pkg, Context context, int mode) {
076: String super ClassName = super Class.getName();
077: String className = super ClassName.replace('.', '_')
078: + "__adapter";
079: return generateSubclass(className, super Class, interfaces, pkg,
080: context, mode);
081: }
082:
083: /**
084: * Generates a class that extends the superClass and implements the
085: * interfaces. Functions in the pkg are mapped to non-final/static
086: * public/protected methods with the same name and the same number of
087: * parameters. Note that this method may throw ClassFormatError.
088: *
089: * @param className
090: * the name of the class to be generated
091: * @param superClass
092: * super class that the generated class extends
093: * @param interfaces
094: * list of interfaces that the generated class implements
095: * @param pkg
096: * a Package that includes functions to be mapped to methods.
097: * @param context
098: * a Context in which functions are extracted from pkg
099: * @param mode
100: * THIS if each function has 'this' parameter, otherwise 0.
101: * @return the generated class
102: */
103: public static Class generateSubclass(String className,
104: Class super Class, Class[] interfaces, Package pkg,
105: Context context, int mode) {
106: return generateSubclass(className, super Class, interfaces,
107: null, pkg, context, mode);
108: }
109:
110: /**
111: * Generates a class that extends the superClass and implements the
112: * interfaces. Functions in the pkg are mapped to non-final/static
113: * public/protected methods with the same name and the same number of
114: * parameters. Note that this method may throw ClassFormatError.
115: *
116: * @param className
117: * the name of the class to be generated
118: * @param superClass
119: * super class that the generated class extends
120: * @param interfaces
121: * list of interfaces that the generated class implements
122: * @param sigs
123: * an array of optional explicit method signature.
124: * If it is null, method signatures are determined by
125: * supertypes' method signature and number of function parameters.
126: * If it isn't null, the array of method signature
127: * is used to determin method signatures.
128: * @param pkg
129: * a Package that includes functions to be mapped to methods.
130: * @param context
131: * a Context in which functions are extracted from pkg
132: * @param mode
133: * THIS if each function has 'this' parameter, otherwise 0.
134: * @return the generated class
135: */
136: public static Class generateSubclass(String className,
137: Class super Class, Class[] interfaces, Signature[] sigs,
138: Package pkg, Context context, int mode) {
139: return generateSubclass(className, super Class, interfaces,
140: sigs, pkg, null, context, mode);
141: }
142:
143: public static Class generateSubclass(String className,
144: Class super Class, Class[] interfaces, Signature[] sigs,
145: Package pkg, Map typeMap, Context context, int mode) {
146: ClassLoader classLoader = context.getClassLoader();
147: if (classLoader == null) {
148: classLoader = Thread.currentThread()
149: .getContextClassLoader();
150: }
151: ClassFileLoader handler = new ClassFileLoader(classLoader);
152: handler.setup(pkg, context);
153: ClassFile cf = getClassFileForSubclass(className, super Class,
154: interfaces, pkg, typeMap, context, mode, sigs);
155:
156: if (DEBUG) {
157: try {
158: FileOutputStream fout = new FileOutputStream("c:/tmp/"
159: + className + ".class");
160: DataOutputStream dout = new DataOutputStream(fout);
161: cf.write(dout);
162: fout.close();
163: System.out.println(className);
164: } catch (Exception e) {
165: e.printStackTrace();
166: }
167: }
168: return (Class) handler.handle(cf);
169: }
170:
171: /**
172: * Generates a subtype of the specified class and instantiates with the
173: * given arguments.
174: *
175: * @param context
176: * the context
177: * @param superClass
178: * the super class to extend
179: * @param interfaces
180: * the interfaces to implement
181: * @param pkg
182: * a Package that includes functions to be mapped to methods.
183: * @param args
184: * the arguments to the constructor
185: */
186: public static Object instantiateSubtype(Context context,
187: Class super Class, Class[] interfaces, Package pkg,
188: Object[] args) {
189: try {
190: if (super Class == null) {
191: super Class = Object.class;
192: }
193: Class cls = generateSubclass(super Class, interfaces, pkg,
194: context, 0);
195: return Runtime.callConstructor(context, cls, args, null);
196: } catch (Throwable t) {
197: throw new PnutsException(t, context);
198: }
199: }
200:
201: /**
202: * Creates a class file image of a subtype of superClass (or some
203: * interfaces) and writes to the output stream.
204: *
205: * @param superClass
206: * super class that the generated class extends
207: * @param interfaces
208: * list of interfaces that the generated class implements
209: * @param pkg
210: * a Package that includes functions to be mapped to methods.
211: * @param context
212: * a Context in which functions are extracted from pkg
213: * @param mode
214: * THIS if each function has 'this' parameter, otherwise 0.
215: */
216: public static ClassFile getClassFileForSubclass(String className,
217: Class super Class, Class[] interfaces, Package pkg,
218: Context context, int mode) {
219: return getClassFileForSubclass(className, super Class,
220: interfaces, pkg, null, context, mode, null);
221: }
222:
223: /**
224: * Creates a class file image of a subtype of superClass (or some
225: * interfaces) and writes to the output stream.
226: *
227: * @param superClass
228: * super class that the generated class extends
229: * @param interfaces
230: * list of interfaces that the generated class implements
231: * @param pkg
232: * a Package that includes functions to be mapped to methods.
233: * @param context
234: * a Context in which functions are extracted from pkg
235: * @param mode
236: * THIS if each function has 'this' parameter, otherwise 0.
237: * @param signatures
238: * signature information
239: */
240: public static ClassFile getClassFileForSubclass(String className,
241: Class super Class, Class[] interfaces, Package pkg,
242: Map typeMap, Context context, int mode,
243: Signature[] signatures) {
244: ClassFile cf = ClassGenerator.createClassFile(className,
245: super Class, interfaces, null);
246: constructor(cf, super Class);
247:
248: cf.addField("_package", "Lpnuts/lang/Package;",
249: (short) (Constants.ACC_PRIVATE | Constants.ACC_STATIC));
250:
251: //
252: // public static void attach(Context, Package);
253: //
254: cf.openMethod("attach",
255: "(Lpnuts/lang/Context;Lpnuts/lang/Package;)V",
256: (short) (Constants.ACC_PUBLIC | Constants.ACC_STATIC));
257:
258: cf.add(Opcode.ALOAD_0);
259: cf.add(Opcode.PUTSTATIC, className, "_context",
260: "Lpnuts/lang/Context;");
261: cf.add(Opcode.ALOAD_1);
262: cf.add(Opcode.PUTSTATIC, className, "_package",
263: "Lpnuts/lang/Package;");
264: cf.add(Opcode.RETURN);
265: cf.closeMethod();
266:
267: if (typeMap != null) {
268: for (Iterator it = typeMap.entrySet().iterator(); it
269: .hasNext();) {
270: Map.Entry entry = (Map.Entry) it.next();
271: String name = (String) entry.getKey();
272: Class type = (Class) entry.getValue();
273: cf.addField(name, Signature.makeSignature(type),
274: Constants.ACC_PRIVATE);
275: }
276: }
277:
278: if (signatures != null && typeMap != null) {
279: defineMethods(cf, pkg, super Class, interfaces, context,
280: mode, signatures);
281: Set sigset = new HashSet();
282: for (int i = 0; i < signatures.length; i++) {
283: sigset.add(signatures[i]);
284: }
285: for (Iterator it = typeMap.entrySet().iterator(); it
286: .hasNext();) {
287: Map.Entry entry = (Map.Entry) it.next();
288: String name = (String) entry.getKey();
289: Class type = (Class) entry.getValue();
290: Signature s = Compiler.getterSignature(type, name);
291: if (!sigset.contains(s)) {
292: generateGetter(cf, name, type, s.getMethodName());
293: }
294: s = Compiler.setterSignature(type, name);
295: if (!sigset.contains(s)) {
296: generateSetter(cf, name, type, s.getMethodName());
297: }
298: }
299:
300: } else {
301: // just for subclass() function
302: defineMethods(cf, pkg, super Class, interfaces, context,
303: mode);
304: }
305:
306: return cf;
307: }
308:
309: static void generateGetter(ClassFile cf, String name, Class type,
310: String methodName) {
311: String className = cf.getClassName();
312: String param = Signature.makeSignature(type);
313: cf.openMethod(methodName, "()" + param, Constants.ACC_PUBLIC);
314: cf.add(Opcode.ALOAD_0);
315: cf.add(Opcode.GETFIELD, className, name, param);
316:
317: if (param.length() == 1) { // primitive
318: char ch = param.charAt(0);
319: switch (ch) {
320: case 'I':
321: case 'S':
322: case 'B':
323: case 'C':
324: case 'Z':
325: cf.add(Opcode.IRETURN);
326: break;
327: case 'J':
328: cf.add(Opcode.LRETURN);
329: break;
330: case 'F':
331: cf.add(Opcode.FRETURN);
332: break;
333: case 'D':
334: cf.add(Opcode.DRETURN);
335: break;
336: }
337: } else {
338: cf.add(Opcode.ARETURN);
339: }
340: cf.closeMethod();
341: }
342:
343: static void generateSetter(ClassFile cf, String name, Class type,
344: String methodName) {
345: String className = cf.getClassName();
346: String param = Signature.makeSignature(type);
347: cf.openMethod(methodName, "(" + param + ")V",
348: Constants.ACC_PUBLIC);
349: cf.add(Opcode.ALOAD_0);
350: if (param.length() == 1) { // primitive
351: char ch = param.charAt(0);
352: switch (ch) {
353: case 'I':
354: case 'S':
355: case 'B':
356: case 'C':
357: case 'Z':
358: cf.add(Opcode.ILOAD_1);
359: cf.add(Opcode.PUTFIELD, className, name, param);
360: break;
361: case 'J':
362: cf.add(Opcode.LLOAD_1);
363: cf.add(Opcode.PUTFIELD, className, name, param);
364: break;
365: case 'F':
366: cf.add(Opcode.FLOAD_1);
367: cf.add(Opcode.PUTFIELD, className, name, param);
368: break;
369: case 'D':
370: cf.add(Opcode.DLOAD_1);
371: cf.add(Opcode.PUTFIELD, className, name, param);
372: break;
373: }
374: } else {
375: cf.add(Opcode.ALOAD_1);
376: cf.add(Opcode.PUTFIELD, className, name, param);
377: }
378: cf.add(Opcode.RETURN);
379: cf.closeMethod();
380: }
381:
382: static void defineMethods(ClassFile cf, Package pkg,
383: Class super Class, Class[] interfaces, Context context,
384: int mode, Signature[] signatures) {
385: for (int i = 0; i < signatures.length; i++) {
386: Signature s = signatures[i];
387: Object value = pkg.get(s.toString(), context);
388: if (value instanceof PnutsFunction) {
389: PnutsFunction func = (PnutsFunction) value;
390: List methods = new ArrayList();
391: if (s.resolve(super Class, interfaces, methods)) {
392: String sig = s.toString();
393: Class returnType = s.returnType;
394: if (returnType == null) {
395: returnType = Object.class;
396: }
397: defineMethod(cf, s.parameterTypes, returnType,
398: s.exceptionTypes, s.modifiers,
399: s.methodName, sig, mode);
400: } else {
401: for (Enumeration e = getFunctions(func); e
402: .hasMoreElements();) {
403: Signature s2 = (Signature) s.clone();
404: Function f = (Function) e.nextElement();
405: int n = f.getNumberOfParameter();
406: if ((mode & THIS) == THIS) {
407: n--;
408: }
409: if ((mode & SUPER) == SUPER) {
410: n--;
411: }
412: if (s.parameterTypes == null) {
413: Class[] p = new Class[n];
414: for (int j = 0; j < n; j++) {
415: p[j] = Object.class;
416: }
417: s2.parameterTypes = p;
418: } else {
419: for (int j = 0; j < n; j++) {
420: if (s2.parameterTypes[j] == null) {
421: s2.parameterTypes[j] = Object.class;
422: }
423: }
424: }
425: if (s2.returnType == null) {
426: s2.returnType = Object.class;
427: }
428: String sig = s.methodName
429: + Signature.makeSignature(
430: s2.parameterTypes,
431: s2.returnType);
432: sig = sig.intern();
433: pkg.set(sig, func, context);
434: defineMethod(cf, s2.parameterTypes,
435: s2.returnType, s.exceptionTypes,
436: Modifier.PUBLIC, s2.methodName, sig,
437: mode);
438: }
439: }
440: }
441: }
442: }
443:
444: static void defineMethods(ClassFile cf, Package pkg,
445: Class super Class, Class[] interfaces, Context context,
446: int mode) {
447: for (Enumeration e = pkg.keys(); e.hasMoreElements();) {
448: String name = (String) e.nextElement();
449: Object value = pkg.get(name, context);
450: if (!(value instanceof PnutsFunction)) {
451: continue;
452: }
453: PnutsFunction func = (PnutsFunction) value;
454: String sig = name;
455: String methodName = name;
456:
457: int idx = methodName.indexOf('(');
458: if (idx >= 0) {
459: methodName = methodName.substring(0, idx);
460: }
461: defineMethods(cf, methodName, sig, func, super Class,
462: interfaces, context, mode);
463: }
464: }
465:
466: static int parseTypes(String sig, Context context, List types) {
467: int idx = sig.indexOf('(');
468: if (idx >= 0) {
469: try {
470: return parseParameterSignature(sig.substring(idx + 1),
471: types, context)
472: + idx + 1;
473: } catch (ClassNotFoundException e) {
474: }
475: }
476: return -1;
477: }
478:
479: static List returnTypeAndExceptions(String sig, Context context) {
480: List types = new ArrayList();
481: try {
482: parseParameterSignature(sig, types, context);
483: } catch (ClassNotFoundException e) {
484: return null;
485: }
486: return types;
487: }
488:
489: public static void constructor(ClassFile cf, Class super Class) {
490: constructor(cf, super Class, null, null, null);
491: }
492:
493: public static void constructor(ClassFile cf, Class super Class,
494: Compiler compiler, Context cc, List assignments) {
495: String className = cf.getClassName();
496:
497: cf.addField("_superCallProxy", "Lpnuts/lang/AbstractData;",
498: Constants.ACC_PRIVATE);
499: if (super Class == null) {
500: super Class = Object.class;
501: }
502: Constructor constructors[] = super Class
503: .getDeclaredConstructors();
504: int count = 0;
505: for (int i = 0; i < constructors.length; i++) {
506: Constructor cons = constructors[i];
507: Class parameterTypes[] = cons.getParameterTypes();
508: String sig = ClassFile.signature(parameterTypes);
509:
510: int mod = cons.getModifiers();
511: short acc;
512: if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod)) {
513: continue;
514: }
515: count++;
516: cf.openMethod("<init>", sig + "V", Constants.ACC_PUBLIC);
517: cf.add(Opcode.ALOAD_0);
518: for (int j = 0, k = 0; j < parameterTypes.length; j++) {
519: Class type = parameterTypes[j];
520: if (type == int.class || type == byte.class
521: || type == short.class || type == char.class
522: || type == boolean.class) {
523: cf.iloadLocal(1 + j + k);
524: } else if (type == long.class) {
525: cf.lloadLocal(1 + j + k);
526: k++;
527: } else if (type == float.class) {
528: cf.floadLocal(1 + j + k);
529: } else if (type == double.class) {
530: cf.dloadLocal(1 + j + k);
531: k++;
532: } else {
533: cf.loadLocal(1 + j + k);
534: }
535: }
536: cf.add(Opcode.INVOKESPECIAL, super Class.getName(),
537: "<init>", sig, "V");
538:
539: assignSuperCallProxy(cf, className);
540:
541: if (compiler != null) {
542: declareFields(cf, cc, compiler, assignments);
543: }
544:
545: cf.add(Opcode.RETURN);
546: cf.closeMethod();
547: }
548: if (count == 0) {
549: cf.openMethod("<init>", "()V", Constants.ACC_PUBLIC);
550: cf.add(Opcode.ALOAD_0);
551: cf.add(Opcode.INVOKESPECIAL, super Class.getName(),
552: "<init>", "()", "V");
553:
554: assignSuperCallProxy(cf, className);
555:
556: if (compiler != null) {
557: declareFields(cf, cc, compiler, assignments);
558: }
559:
560: cf.add(Opcode.RETURN);
561: cf.closeMethod();
562: }
563: }
564:
565: private static void declareFields(ClassFile cf, Context cc,
566: Compiler compiler, List assignments) {
567: String className = cf.getClassName();
568: for (int i = 0, n = assignments.size(); i < n; i++) {
569: SimpleNode assign = (SimpleNode) assignments.get(i);
570: SimpleNode lhs = assign.jjtGetChild(0);
571: SimpleNode rhs = assign.jjtGetChild(1);
572: cf.add(Opcode.GETSTATIC, className, "_context",
573: "Lpnuts/lang/Context;");
574: cf.add(Opcode.ALOAD_0); // this
575: cf.add(Opcode.LDC, cf.addConstant(lhs.str));
576: rhs.accept(compiler, cc);
577: cf
578: .add(
579: Opcode.INVOKESTATIC,
580: "pnuts.lang.Runtime",
581: "putField",
582: "(Lpnuts/lang/Context;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)",
583: "V");
584: }
585: }
586:
587: /*
588: * this._superCallProxy = new SuperCallProxy(this);
589: */
590: private static void assignSuperCallProxy(ClassFile cf,
591: String className) {
592: cf.add(Opcode.ALOAD_0);
593: cf.add(Opcode.NEW, SUPER_PROXY_NAME);
594: cf.add(Opcode.DUP);
595: cf.add(Opcode.ALOAD_0);
596: cf.add(Opcode.INVOKESPECIAL, SUPER_PROXY_NAME, "<init>",
597: "(Ljava/lang/Object;)", "V");
598: cf.add(Opcode.PUTFIELD, className, "_superCallProxy",
599: "Lpnuts/lang/AbstractData;");
600: }
601:
602: private static void defineMethods(ClassFile cf, String name,
603: String sig, PnutsFunction func, Class super Class,
604: Class[] interfaces, Context context, int mode) {
605: Hashtable methods = new Hashtable();
606: int count = 0;
607: if (interfaces != null) {
608: loop1: for (int i = 0; i < interfaces.length; i++) {
609: Class _interface = interfaces[i];
610: Method[] _methods = _interface.getMethods();
611: for (int j = 0; j < _methods.length; j++) {
612: Method m = _methods[j];
613: int modifiers = m.getModifiers();
614: if (!Modifier.isPublic(modifiers)
615: && !Modifier.isProtected(modifiers)
616: || Modifier.isStatic(modifiers)
617: || Modifier.isFinal(modifiers)) {
618: continue;
619: }
620: Class[] parameterTypes = m.getParameterTypes();
621: Class[] exceptionTypes = m.getExceptionTypes();
622: String signature = name
623: + ClassFile.signature(parameterTypes);
624: int expected_args = parameterTypes.length;
625:
626: if ((mode & THIS) == THIS) {
627: expected_args++;
628: }
629: if ((mode & SUPER) == SUPER) {
630: expected_args++;
631: }
632: if (m.getName().equals(name)
633: && func.defined(expected_args)) {
634: if (sig == name) { // no type info
635: if (methods.get(signature) == null) {
636: defineMethod(cf, parameterTypes, m
637: .getReturnType(),
638: exceptionTypes,
639: Modifier.PUBLIC, name, sig,
640: mode);
641: methods.put(signature, signature);
642: count++;
643: }
644: } else {
645: if (!sig.equals(signature)) {
646: continue;
647: }
648: if (methods.get(signature) == null) {
649: defineMethod(cf, parameterTypes, m
650: .getReturnType(),
651: exceptionTypes,
652: Modifier.PUBLIC, name, sig,
653: mode);
654: methods.put(signature, signature);
655: count++;
656: }
657: }
658: }
659: }
660: }
661: }
662: if (super Class == null) {
663: super Class = Object.class;
664: }
665: while (super Class != null) {
666: Method[] _methods = ReflectionUtil
667: .getInheritableMethods(super Class);
668:
669: loop2: for (int j = 0; j < _methods.length; j++) {
670: Method m = _methods[j];
671: int modifiers = m.getModifiers();
672: if (!Modifier.isPublic(modifiers)
673: && !Modifier.isProtected(modifiers)
674: || Modifier.isStatic(modifiers)
675: || Modifier.isFinal(modifiers)) {
676: continue;
677: }
678: Class[] parameterTypes = m.getParameterTypes();
679: Class[] exceptionTypes = m.getExceptionTypes();
680: String signature = name
681: + ClassFile.signature(parameterTypes);
682: int expected_args = parameterTypes.length;
683: if ((mode & THIS) == THIS) {
684: expected_args++;
685: }
686: if ((mode & SUPER) == SUPER) {
687: expected_args++;
688: }
689: if (m.getName().equals(name)
690: && func.defined(expected_args)) {
691: if (sig == name) { // no type info
692: if (methods.get(signature) == null) {
693: defineMethod(cf, parameterTypes, m
694: .getReturnType(), exceptionTypes,
695: Modifier.PUBLIC, name, sig, mode);
696: methods.put(signature, signature);
697: count++;
698: }
699: } else {
700: if (!sig.equals(signature)) {
701: continue;
702: }
703: if (methods.get(signature) == null) {
704: defineMethod(cf, parameterTypes, m
705: .getReturnType(), exceptionTypes,
706: Modifier.PUBLIC, name, sig, mode);
707: methods.put(signature, signature);
708: count++;
709: }
710: }
711: }
712: }
713: super Class = super Class.getSuperclass();
714: }
715:
716: if (count == 0) { // when not override
717: Enumeration ee = getFunctions(func);
718: if (ee != null) {
719: Function f = (Function) ee.nextElement();
720: int narg = f.getNumberOfParameter();
721: if ((mode & THIS) == THIS && narg > 0) {
722: narg--;
723: }
724: if ((mode & SUPER) == SUPER && narg > 0) {
725: narg--;
726: }
727: Class[] parameterTypes = new Class[narg];
728: Class[] exceptionTypes = null;
729: Class returnType;
730: List types = null;
731: int pos = -1;
732: if (sig != name) {
733: types = new ArrayList();
734: pos = parseTypes(sig, context, types);
735: }
736: if (pos == -1) { // no type info
737: for (int i = 0; i < narg; i++) {
738: parameterTypes[i] = Object.class;
739: }
740:
741: returnType = Object.class;
742: } else {
743: for (int i = 0; i < narg; i++) {
744: parameterTypes[i] = (Class) types.get(i);
745: }
746: types = returnTypeAndExceptions(sig.substring(pos),
747: context);
748:
749: returnType = (Class) types.get(0);
750: if (types.size() > 1) {
751: exceptionTypes = new Class[types.size() - 1];
752: for (int i = 0; i < exceptionTypes.length; i++) {
753: exceptionTypes[i] = (Class) types
754: .get(1 + i);
755: }
756: }
757: }
758: defineMethod(cf, parameterTypes, returnType,
759: exceptionTypes, Modifier.PUBLIC, name, sig,
760: mode);
761: }
762: }
763: }
764:
765: public static void defineMethod(ClassFile cf,
766: Class[] parameterTypes, Class returnType,
767: Class[] exceptionTypes, int modifiers, String methodName,
768: String sig, int mode) {
769: ClassGenerator.defineMethod(cf, parameterTypes, returnType,
770: exceptionTypes, modifiers, methodName, sig, mode);
771: }
772:
773: private static int parseParameterSignature(String signature,
774: List types, Context context) throws ClassNotFoundException {
775: char[] c = signature.toCharArray();
776: int index = 0;
777: int dim = 0;
778: // boolean returnPart = false;
779: loop: while (index < c.length) {
780: switch (c[index]) {
781: case 'V':
782: types.add(void.class);
783: dim = 0;
784: index++;
785: break;
786: case 'J':
787: types.add(Runtime.arrayType(Long.TYPE, dim));
788: dim = 0;
789: index++;
790: break;
791: case 'D':
792: types.add(Runtime.arrayType(Double.TYPE, dim));
793: dim = 0;
794: index++;
795: break;
796: case 'B':
797: types.add(Runtime.arrayType(Byte.TYPE, dim));
798: dim = 0;
799: index++;
800: break;
801: case 'S':
802: types.add(Runtime.arrayType(Short.TYPE, dim));
803: dim = 0;
804: index++;
805: break;
806: case 'C':
807: types.add(Runtime.arrayType(Character.TYPE, dim));
808: dim = 0;
809: index++;
810: break;
811: case 'I':
812: types.add(Runtime.arrayType(Integer.TYPE, dim));
813: dim = 0;
814: index++;
815: break;
816: case 'Z':
817: types.add(Runtime.arrayType(Boolean.TYPE, dim));
818: dim = 0;
819: index++;
820: break;
821: case 'F':
822: types.add(Runtime.arrayType(Float.TYPE, dim));
823: dim = 0;
824: index++;
825: break;
826: case '[':
827: while (c[index] == '[') {
828: dim++;
829: index++;
830: }
831: break;
832: case 'L':
833: int start = index + 1;
834: while (c[index++] != ';') {
835: }
836: String cn = new String(c, start, index - start - 1);
837: types.add(Runtime.arrayType(Pnuts.loadClass(cn.replace(
838: '/', '.'), context), dim));
839: dim = 0;
840: break;
841: case ')':
842: // returnPart = true;
843: index++;
844: // continue loop;
845: break loop;
846: default:
847: throw new PnutsException("illegal method signature",
848: context);
849: }
850: // if (returnPart){
851: // break loop;
852: // }
853: }
854: return index;
855: }
856:
857: /**
858: * Generates an interface
859: *
860: * @param name
861: * the name of the interface
862: * @param superInterfaces
863: * an array of super interface
864: * @param signatures
865: * an array of method signatures
866: * @param context
867: * the context in which the classes are loaded
868: * @return the generated interface
869: */
870: public static Class generateInterface(String name,
871: Class[] super Interfaces, String[] signatures,
872: Context context) {
873: return generateInterface(
874: name,
875: super Interfaces,
876: signatures,
877: context,
878: (short) (Constants.ACC_PUBLIC | Constants.ACC_INTERFACE));
879: }
880:
881: /**
882: * Generates an interface
883: *
884: * @param name
885: * the name of the interface
886: * @param superInterfaces
887: * an array of super interface
888: * @param signatures
889: * an array of method signatures
890: * @param context
891: * the context in which the classes are loaded
892: * @param modifiers
893: * the modifiers of the interface
894: * @return the generated interface
895: */
896: public static Class generateInterface(String name,
897: Class[] super Interfaces, String[] signatures,
898: Context context, short modifiers) {
899: ClassLoader classLoader = context.getClassLoader();
900: if (classLoader == null) {
901: classLoader = Thread.currentThread()
902: .getContextClassLoader();
903: }
904: ClassFileLoader handler = new ClassFileLoader(classLoader);
905: ClassFile cf = getClassFileForInterface(name, super Interfaces,
906: signatures, context, modifiers);
907: return (Class) handler.handle(cf);
908: }
909:
910: public static ClassFile getClassFileForInterface(String name,
911: Class[] super Interfaces, String[] signatures,
912: Context context, short modifiers) {
913: ClassFile cf = new ClassFile(name, "java.lang.Object", null,
914: modifiers);
915: if (super Interfaces != null) {
916: for (int i = 0; i < super Interfaces.length; i++) {
917: cf.addInterface(super Interfaces[i].getName());
918: }
919: }
920: if (signatures != null) {
921: for (int i = 0; i < signatures.length; i++) {
922: String sig = signatures[i];
923: List types = new ArrayList();
924: int idx0 = sig.indexOf('(');
925: if (idx0 < 0) {
926: continue;
927: }
928: String methodName = sig.substring(0, idx0);
929: int idx = parseTypes(sig, context, types);
930: Class[] parameterTypes = new Class[types.size()];
931: types.toArray(parameterTypes);
932: if (idx > 0) {
933: List types2 = returnTypeAndExceptions(sig
934: .substring(idx), context);
935: Class returnType = (Class) types2.get(0);
936: String[] exceptionTypeInfo = null;
937: if (types2.size() > 1) {
938: exceptionTypeInfo = new String[types2.size() - 1];
939: for (int j = 0; j < exceptionTypeInfo.length; j++) {
940: exceptionTypeInfo[j] = ((Class) types2
941: .get(j + 1)).getName();
942: }
943: }
944: cf
945: .openMethod(
946: methodName,
947: Signature.makeSignature(
948: parameterTypes, returnType),
949: (short) (Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT),
950: exceptionTypeInfo);
951: cf.closeMethod();
952: }
953: }
954: }
955: return cf;
956: }
957:
958: public static ClassLoader mergeClassLoader(Class[] types,
959: ClassLoader loader) {
960: ArrayList classLoaders = new ArrayList();
961: for (int i = 0; i < types.length; i++) {
962: Class type = types[i];
963: try {
964: if (loader.loadClass(type.getName()) == type) {
965: continue;
966: }
967: } catch (Exception e) {
968: }
969: classLoaders.add(type.getClassLoader());
970: }
971: int size = classLoaders.size();
972: if (size > 0) {
973: ClassLoader[] cl = new ClassLoader[size];
974: classLoaders.toArray(cl);
975: return new MultiClassLoader(loader, cl);
976: } else {
977: return loader;
978: }
979: }
980: }
|