KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > python > core > PyType


1 package org.python.core;
2
3 import java.io.Serializable JavaDoc;
4 import java.lang.reflect.Constructor JavaDoc;
5 import java.lang.reflect.Field JavaDoc;
6 import java.lang.reflect.Method JavaDoc;
7 import java.lang.reflect.Modifier JavaDoc;
8 import java.util.ArrayList JavaDoc;
9 import java.util.HashMap JavaDoc;
10 import java.util.Iterator JavaDoc;
11
12 /**
13  * first-class Python type.
14  *
15  */

16 public class PyType extends PyObject {
17     /* type info */
18
19     public static final String JavaDoc exposed_name = "type";
20
21     public static void typeSetup(PyObject dict, PyType.Newstyle marker) {
22         dict.__setitem__("__dict__", new PyGetSetDescr("__dict__",
23                 PyType.class, "getDict", null));
24         dict.__setitem__("__name__", new PyGetSetDescr("__name__",
25                 PyType.class, "fastGetName", null));
26         dict.__setitem__("__base__", new PyGetSetDescr("__base__",
27                 PyType.class, "getBase", null));
28         dict.__setitem__("__bases__", new PyGetSetDescr("__bases__",
29                 PyType.class, "getBases", null));
30         class exposed___getattribute__ extends PyBuiltinFunctionNarrow {
31
32             private PyType self;
33
34             public PyObject getSelf() {
35                 return self;
36             }
37
38             exposed___getattribute__(PyType self, PyBuiltinFunction.Info info) {
39                 super(info);
40                 this.self = self;
41             }
42
43             public PyBuiltinFunction makeBound(PyObject self) {
44                 return new exposed___getattribute__((PyType) self, info);
45             }
46
47             public PyObject __call__(PyObject arg0) {
48                 try {
49                     String JavaDoc name = (arg0.asName(0));
50                     PyObject ret = self.type___findattr__(name);
51                     if (ret == null)
52                         self.noAttributeError(name);
53                     return ret;
54                 } catch (PyObject.ConversionException e) {
55                     String JavaDoc msg;
56                     switch (e.index) {
57                     case 0:
58                         msg = "attribute name must be string";
59                         break;
60                     default:
61                         msg = "xxx";
62                     }
63                     throw Py.TypeError(msg);
64                 }
65             }
66
67             public PyObject inst_call(PyObject gself, PyObject arg0) {
68                 PyType self = (PyType) gself;
69                 try {
70                     String JavaDoc name = (arg0.asName(0));
71                     PyObject ret = self.type___findattr__(name);
72                     if (ret == null)
73                         self.noAttributeError(name);
74                     return ret;
75                 } catch (PyObject.ConversionException e) {
76                     String JavaDoc msg;
77                     switch (e.index) {
78                     case 0:
79                         msg = "attribute name must be string";
80                         break;
81                     default:
82                         msg = "xxx";
83                     }
84                     throw Py.TypeError(msg);
85                 }
86             }
87
88         }
89         dict.__setitem__("__getattribute__", new PyMethodDescr(
90                 "__getattribute__", PyType.class, 1, 1,
91                 new exposed___getattribute__(null, null)));
92         class exposed___setattr__ extends PyBuiltinFunctionNarrow {
93
94             private PyType self;
95
96             public PyObject getSelf() {
97                 return self;
98             }
99
100             exposed___setattr__(PyType self, PyBuiltinFunction.Info info) {
101                 super(info);
102                 this.self = self;
103             }
104
105             public PyBuiltinFunction makeBound(PyObject self) {
106                 return new exposed___setattr__((PyType) self, info);
107             }
108
109             public PyObject __call__(PyObject arg0, PyObject arg1) {
110                 try {
111                     self.type___setattr__(arg0.asName(0), arg1);
112                     return Py.None;
113                 } catch (PyObject.ConversionException e) {
114                     String JavaDoc msg;
115                     switch (e.index) {
116                     case 0:
117                         msg = "attribute name must be string";
118                         break;
119                     default:
120                         msg = "xxx";
121                     }
122                     throw Py.TypeError(msg);
123                 }
124             }
125
126             public PyObject inst_call(PyObject gself, PyObject arg0,
127                     PyObject arg1) {
128                 PyType self = (PyType) gself;
129                 try {
130                     self.type___setattr__(arg0.asName(0), arg1);
131                     return Py.None;
132                 } catch (PyObject.ConversionException e) {
133                     String JavaDoc msg;
134                     switch (e.index) {
135                     case 0:
136                         msg = "attribute name must be string";
137                         break;
138                     default:
139                         msg = "xxx";
140                     }
141                     throw Py.TypeError(msg);
142                 }
143             }
144
145         }
146         dict.__setitem__("__setattr__", new PyMethodDescr("__setattr__",
147                 PyType.class, 2, 2, new exposed___setattr__(null, null)));
148         class exposed___delattr__ extends PyBuiltinFunctionNarrow {
149
150             private PyType self;
151
152             public PyObject getSelf() {
153                 return self;
154             }
155
156             exposed___delattr__(PyType self, PyBuiltinFunction.Info info) {
157                 super(info);
158                 this.self = self;
159             }
160
161             public PyBuiltinFunction makeBound(PyObject self) {
162                 return new exposed___delattr__((PyType) self, info);
163             }
164
165             public PyObject __call__(PyObject arg0) {
166                 try {
167                     self.type___delattr__(arg0.asName(0));
168                     return Py.None;
169                 } catch (PyObject.ConversionException e) {
170                     String JavaDoc msg;
171                     switch (e.index) {
172                     case 0:
173                         msg = "attribute name must be string";
174                         break;
175                     default:
176                         msg = "xxx";
177                     }
178                     throw Py.TypeError(msg);
179                 }
180             }
181
182             public PyObject inst_call(PyObject gself, PyObject arg0) {
183                 PyType self = (PyType) gself;
184                 try {
185                     self.type___delattr__(arg0.asName(0));
186                     return Py.None;
187                 } catch (PyObject.ConversionException e) {
188                     String JavaDoc msg;
189                     switch (e.index) {
190                     case 0:
191                         msg = "attribute name must be string";
192                         break;
193                     default:
194                         msg = "xxx";
195                     }
196                     throw Py.TypeError(msg);
197                 }
198             }
199
200         }
201         dict.__setitem__("__delattr__", new PyMethodDescr("__delattr__",
202                 PyType.class, 1, 1, new exposed___delattr__(null, null)));
203         class exposed___subclasses__ extends PyBuiltinFunctionNarrow {
204
205             private PyType self;
206
207             public PyObject getSelf() {
208                 return self;
209             }
210
211             exposed___subclasses__(PyType self, PyBuiltinFunction.Info info) {
212                 super(info);
213                 this.self = self;
214             }
215
216             public PyBuiltinFunction makeBound(PyObject self) {
217                 return new exposed___subclasses__((PyType) self, info);
218             }
219
220             public PyObject __call__() {
221                 return self.type_getSubclasses();
222             }
223
224             public PyObject inst_call(PyObject gself) {
225                 PyType self = (PyType) gself;
226                 return self.type_getSubclasses();
227             }
228
229         }
230         dict.__setitem__("__subclasses__", new PyMethodDescr("__subclasses__",
231                 PyType.class, 0, 0, new exposed___subclasses__(null, null)));
232         class exposed___call__ extends PyBuiltinFunctionWide {
233
234             private PyType self;
235
236             public PyObject getSelf() {
237                 return self;
238             }
239
240             exposed___call__(PyType self, PyBuiltinFunction.Info info) {
241                 super(info);
242                 this.self = self;
243             }
244
245             public PyBuiltinFunction makeBound(PyObject self) {
246                 return new exposed___call__((PyType) self, info);
247             }
248
249             public PyObject inst_call(PyObject self, PyObject[] args) {
250                 return inst_call(self, args, Py.NoKeywords);
251             }
252
253             public PyObject __call__(PyObject[] args) {
254                 return __call__(args, Py.NoKeywords);
255             }
256
257             public PyObject __call__(PyObject[] args, String JavaDoc[] keywords) {
258                 return self.type___call__(args, keywords);
259             }
260
261             public PyObject inst_call(PyObject gself, PyObject[] args,
262                     String JavaDoc[] keywords) {
263                 PyType self = (PyType) gself;
264                 return self.type___call__(args, keywords);
265             }
266
267         }
268         dict.__setitem__("__call__", new PyMethodDescr("__call__",
269                 PyType.class, -1, -1, new exposed___call__(null, null)));
270         dict.__setitem__("__new__", new PyNewWrapper(PyType.class, "__new__",
271                 -1, -1) {
272
273             public PyObject new_impl(boolean init, PyType subtype,
274                     PyObject[] args, String JavaDoc[] keywords) {
275                 return type_new(this, init, subtype, args, keywords);
276             }
277
278         });
279     }
280
281     public static PyObject type_new(PyObject new_, boolean init,
282             PyType subtype, PyObject[] args, String JavaDoc[] keywords) {
283         if (args.length == 1 && keywords.length == 0) {
284             return args[0].getType();
285         }
286         if (args.length + keywords.length != 3)
287             throw Py.TypeError("type() takes exactly 1 or 3 arguments");
288         ArgParser ap = new ArgParser("type()", args, keywords, "name", "bases",
289                 "dict");
290         String JavaDoc name = ap.getString(0);
291         PyObject bases = ap.getPyObject(1);
292         if (!(bases instanceof PyTuple))
293             throw Py.TypeError("type(): bases must be tuple");
294         PyObject dict = ap.getPyObject(2);
295         if (!(dict instanceof PyDictionary || dict instanceof PyStringMap))
296             throw Py.TypeError("type(): dict must be dict");
297         return newType(new_, subtype, name, (PyTuple) bases, dict);
298
299     }
300
301
302     public PyObject getStatic() {
303         PyType cur = this;
304         while (cur.underlying_class == null) {
305             cur = cur.base;
306         }
307         return cur;
308     }
309
310     public PyObject getBase() {
311         if (base == null)
312             return Py.None;
313         return base;
314     }
315
316     public PyObject getBases() {
317         if (bases == null)
318             return new PyTuple();
319         return new PyTuple(bases);
320     }
321
322     public PyObject instDict() {
323         if (needs_userdict) {
324             return new PyStringMap();
325         }
326         return null;
327     }
328
329     private String JavaDoc name;
330     private PyType base;
331     private PyObject[] bases;
332     private PyObject dict;
333     private PyObject[] mro;
334     private Class JavaDoc underlying_class;
335
336     private boolean non_instantiable = false;
337
338     boolean has_set, has_delete;
339
340     private boolean needs_finalizer;
341
342     private int nuserslots;
343     private boolean needs_userdict;
344
345     private java.lang.ref.ReferenceQueue JavaDoc subclasses_refq = new java.lang.ref.ReferenceQueue JavaDoc();
346     private java.util.HashSet JavaDoc subclasses = new java.util.HashSet JavaDoc();
347
348     private void cleanup_subclasses() {
349         java.lang.ref.Reference JavaDoc ref;
350         while ((ref = subclasses_refq.poll()) != null) {
351             subclasses.remove(ref);
352         }
353     }
354
355     public synchronized final PyObject type_getSubclasses() {
356         PyList result = new PyList();
357         cleanup_subclasses();
358         for (java.util.Iterator JavaDoc iter =subclasses.iterator(); iter.hasNext();) {
359             java.lang.ref.WeakReference JavaDoc type_ref = (java.lang.ref.WeakReference JavaDoc)iter.next();
360             PyType subtype = (PyType)type_ref.get();
361             if (subtype == null)
362                 continue;
363             result.append(subtype);
364         }
365         return result;
366     }
367
368     private synchronized void attachSubclass(PyType subtype) {
369         cleanup_subclasses();
370         subclasses.add(
371             new java.lang.ref.WeakReference JavaDoc(subtype, subclasses_refq));
372     }
373
374     private interface OnType {
375         boolean onType(PyType type);
376     }
377
378     private synchronized void traverse_hierarchy(boolean top, OnType behavior) {
379         boolean stop = false;
380         if (!top) {
381             stop = behavior.onType(this);
382         }
383         if (stop)
384             return;
385         for (java.util.Iterator JavaDoc iter = subclasses.iterator();
386             iter.hasNext();
387             ) {
388             java.lang.ref.WeakReference JavaDoc type_ref =
389                 (java.lang.ref.WeakReference JavaDoc) iter.next();
390             PyType subtype = (PyType) type_ref.get();
391             if (subtype == null)
392                 continue;
393             subtype.traverse_hierarchy(false, behavior);
394         }
395     }
396
397     private static void fill_classic_mro(ArrayList JavaDoc acc,PyClass classic_cl) {
398         if(!acc.contains(classic_cl))
399             acc.add(classic_cl);
400         PyObject[] bases = classic_cl.__bases__.getArray();
401         for (int i=0; i <bases.length; i++) {
402             fill_classic_mro(acc,(PyClass)bases[i]);
403         }
404     }
405
406     private static PyObject[] classic_mro(PyClass classic_cl) {
407         ArrayList JavaDoc acc = new ArrayList JavaDoc();
408
409
410         return (PyObject[])acc.toArray(new PyObject[0]);
411     }
412
413     private static boolean tail_contains(PyObject[] lst,int whence,PyObject o) {
414         int n = lst.length;
415         for (int i=whence+1; i < n; i++) {
416             if (lst[i] == o)
417                 return true;
418         }
419         return false;
420     }
421
422     private static PyException mro_error(PyObject[][] to_merge,int[] remain) {
423         StringBuffer JavaDoc msg = new StringBuffer JavaDoc("Cannot create a"+
424             " consistent method resolution\norder (MRO) for bases ");
425         PyDictionary set = new PyDictionary();
426         for (int i=0; i < to_merge.length; i++) {
427             PyObject[] lst = to_merge[i];
428             if(remain[i] < lst.length)
429                 set.__setitem__(lst[remain[i]],Py.None);
430         }
431         PyObject iter = set.__iter__();
432         PyObject cur;
433         boolean subq = false;
434         while ((cur = iter.__iternext__()) != null) {
435             PyObject name = cur.__findattr__("__name__");
436             if (!subq) {
437                 subq = true;
438             } else {
439                 msg.append(", ");
440             }
441             msg.append(name==null?"?":name.toString());
442         }
443         return Py.TypeError(msg.toString());
444     }
445
446       private static void debug(PyObject[] objs) {
447          System.out.println(new PyList(objs).toString());
448       }
449
450     final PyObject[] type_mro() {
451         PyObject[] bases = this.bases;
452         int n = bases.length;
453         for (int i=0; i < n; i++) {
454             PyObject cur = bases[i];
455             for (int j = i+1; j<n; j++) {
456                 if (bases[j] == cur) {
457                     PyObject name = cur.__findattr__("__name__");
458                     throw Py.TypeError("duplicate base class " +
459                         (name==null?"?":name.toString()));
460                 }
461             }
462         }
463
464         int nmerge = n+1;
465
466         PyObject[][] to_merge = new PyObject[nmerge][];
467         int[] remain = new int[nmerge];
468
469         for (int i=0; i < n; i++) {
470             PyObject cur = bases[i];
471             remain[i] = 0;
472             if (cur instanceof PyType) {
473                 to_merge[i] = ((PyType)cur).mro;
474             } else if (cur instanceof PyClass) {
475                 to_merge[i] = classic_mro((PyClass)cur);
476             }
477         }
478
479         to_merge[n] = bases;
480         remain[n] = 0;
481
482         ArrayList JavaDoc acc = new ArrayList JavaDoc();
483         acc.add(this);
484
485         int empty_cnt=0;
486
487         scan : for (int i = 0; i < nmerge; i++) {
488             PyObject candidate;
489             PyObject[] cur = to_merge[i];
490             if (remain[i] >= cur.length) {
491                 empty_cnt++;
492                 continue scan;
493             }
494
495             candidate = cur[remain[i]];
496             for (int j = 0; j < nmerge; j++)
497                 if (tail_contains(to_merge[j],remain[j],candidate))
498                     continue scan;
499             acc.add(candidate);
500             for (int j = 0; j < nmerge; j++) {
501                 if (remain[j]<to_merge[j].length &&
502                     to_merge[j][remain[j]]==candidate)
503                     remain[j]++;
504             }
505             // restart scan
506
i = -1;
507             empty_cnt = 0;
508         }
509         if (empty_cnt == nmerge) {
510             return (PyObject[])acc.toArray(bases);
511         }
512         throw mro_error(to_merge,remain);
513     }
514
515     private static PyType solid_base(PyType base) {
516         PyObject[] mro = base.mro;
517         for (int i=0; i<mro.length; i++) {
518             PyObject parent = mro[i];
519             if (parent instanceof PyType) {
520                 PyType parent_type =(PyType)parent;
521                 if (parent_type.underlying_class != null || parent_type.nuserslots != 0)
522                     return parent_type;
523             }
524         }
525         throw Py.TypeError("base without solid base");
526     }
527
528     private static PyType best_base(PyObject[] bases_list) {
529         PyType winner=null;
530         PyType candidate=null;
531         PyType base=null;
532         for (int i=0; i < bases_list.length;i++) {
533             PyObject base_proto = bases_list[i];
534             if (base_proto instanceof PyClass)
535                 continue;
536             if (!(base_proto instanceof PyType))
537                 throw Py.TypeError("bases must be types");
538             PyType base_i = (PyType)base_proto;
539             candidate = solid_base(base_i);
540             if (winner == null) {
541                 winner = candidate;
542                 base = base_i;
543             } else if (winner.isSubType(candidate)) {
544                 ;
545             } else if (candidate.isSubType(winner)) {
546                 winner = candidate;
547                 base = base_i;
548             } else {
549                 throw Py.TypeError("multiple bases have instance lay-out conflict");
550             }
551         }
552         if (base == null)
553             throw Py.TypeError("a new-style class can't have only classic bases");
554         return base;
555     }
556
557     public static PyObject newType(PyObject new_,PyType metatype,String JavaDoc name,PyTuple bases,PyObject dict) {
558         PyType object_type = fromClass(PyObject.class);
559
560         PyObject[] bases_list = bases.getArray();
561         PyType winner = metatype;
562         for (int i=0; i<bases_list.length; i++) {
563             PyObject bases_i = bases_list[i];
564             if (bases_i instanceof PyJavaClass)
565                 throw Py.TypeError("can't mix new-style and java classes");
566             if (bases_i instanceof PyClass) {
567                 if (((PyClass)bases_i).proxyClass != null)
568                     throw Py.TypeError("can't mix new-style and java classes");
569                 continue;
570             }
571             PyType curtype = bases_i.getType();
572             if (winner.isSubType(curtype))
573                 continue;
574             if (curtype.isSubType(winner)) {
575                 winner = curtype;
576                 continue;
577             }
578             throw Py.TypeError("metaclass conflict: "+
579                 "the metaclass of a derived class "+
580                 "must be a (non-strict) subclass "+
581                 "of the metaclasses of all its bases");
582         }
583         if (winner != metatype) {
584             PyObject winner_new_ = winner.lookup("__new__");
585             if (winner_new_ !=null && winner_new_ != new_) {
586                 return invoke_new_(new_,winner,false,new PyObject[] {new PyString(name),bases,dict},Py.NoKeywords);
587             }
588             metatype = winner;
589         }
590         if (bases_list.length == 0) {
591             bases_list = new PyObject[] {object_type};
592         }
593
594         PyType base = best_base(bases_list);
595
596         // xxx can be subclassed ?
597

598         boolean needs_userdict = base.needs_userdict;
599         if (!needs_userdict) {
600             for (int i=0; i<bases_list.length;i++) {
601                 PyObject cur = bases_list[i];
602                 if (cur != base) {
603                     if ((cur instanceof PyType && ((PyType)cur).needs_userdict) || cur instanceof PyClass) {
604                         needs_userdict = true;
605                         break;
606                     }
607                 }
608             }
609         }
610
611         int nuserslots = base.nuserslots;
612
613         needs_userdict = true;
614
615         if (dict.__finditem__("__module__") == null) {
616            PyFrame frame = Py.getFrame();
617            if (frame != null) {
618                PyObject globals = frame.f_globals;
619                PyObject modname;
620                if ((modname = globals.__finditem__("__name__")) != null) {
621                    dict.__setitem__("__module__", modname);
622                }
623            }
624         }
625
626         // xxx also __doc__ __module__
627
// xxx __slots__!
628

629         PyType newtype = new PyType(); // xxx set metatype
630

631         newtype.name = name;
632         newtype.base = base;
633         newtype.bases = bases_list;
634
635         newtype.needs_userdict = needs_userdict;
636         newtype.nuserslots = nuserslots;
637
638         newtype.dict = dict;
639
640         // special case __new__, if function => static method
641
PyObject tmp = dict.__finditem__("__new__");
642         if (tmp != null && tmp instanceof PyFunction) { // xxx java functions?
643
dict.__setitem__("__new__",new PyStaticMethod(tmp));
644         }
645
646         PyObject mro_meth = null;
647         PyObject[] newmro;
648
649         if (metatype.underlying_class != PyType.class)
650             mro_meth = metatype.lookup("mro");
651
652         if (mro_meth == null) {
653             newmro = newtype.type_mro();
654         } else {
655             newmro = Py.make_array(mro_meth.__get__(newtype,metatype).__call__());
656         }
657
658         newtype.mro = newmro;
659
660         // __dict__ descriptor
661
if (needs_userdict && newtype.lookup("__dict__")==null) {
662             dict.__setitem__("__dict__",new PyGetSetDescr(newtype,"__dict__",PyObject.class,"getDict",null));
663         }
664
665         newtype.has_set = newtype.lookup("__set__") != null;
666         newtype.has_delete = newtype.lookup("__delete__") != null;
667
668         newtype.needs_finalizer = newtype.lookup("__del__") != null;
669
670         for (int i=0; i<bases_list.length;i++) {
671             PyObject cur = bases_list[i];
672             if (cur instanceof PyType)
673                 ((PyType)cur).attachSubclass(newtype);
674         }
675
676         return newtype;
677     }
678
679
680     public String JavaDoc fastGetName() {
681         return name;
682     }
683
684     public boolean isSubType(PyType supertype) {
685         PyObject[] mro = this.mro;
686         for (int i = 0; i < mro.length; i++) {
687             if (mro[i] == supertype)
688                 return true;
689         }
690         return false;
691     }
692
693     /**
694      * INTERNAL
695      * lookup for name through mro objects' dicts
696      *
697      * @param name attribute name (must be interned)
698      * @return found object or null
699      */

700     public PyObject lookup(String JavaDoc name) {
701         PyObject[] mro = this.mro;
702         for (int i = 0; i < mro.length; i++) {
703             PyObject dict = mro[i].fastGetDict();
704             if (dict != null) {
705                 PyObject obj = dict.__finditem__(name);
706                 if (obj != null)
707                     return obj;
708             }
709         }
710         return null;
711     }
712
713     public PyObject super_lookup(PyType ref,String JavaDoc name) {
714         PyObject[] mro = this.mro;
715         int i;
716         for (i=0; i < mro.length; i++) {
717             if (mro[i] == ref)
718                 break;
719         }
720         i++;
721         for (; i < mro.length; i++) {
722             PyObject dict = mro[i].fastGetDict();
723             if (dict != null) {
724                 PyObject obj = dict.__finditem__(name);
725                 if (obj != null)
726                     return obj;
727             }
728         }
729         return null;
730     }
731
732     private PyType(boolean dummy) {
733         super(true);
734     }
735
736     private PyType() {
737     }
738
739     private static String JavaDoc decapitalize(String JavaDoc s) {
740         char c0 = s.charAt(0);
741         if (Character.isUpperCase(c0)) {
742             if (s.length() > 1 && Character.isUpperCase(s.charAt(1)))
743                 return s;
744             char[] cs = s.toCharArray();
745             cs[0] = Character.toLowerCase(c0);
746             return new String JavaDoc(cs);
747         } else {
748             return s;
749         }
750     }
751
752     private static String JavaDoc normalize_name(String JavaDoc name) {
753         if (name.endsWith("$"))
754             name = name.substring(0, name.length() - 1);
755         return name.intern();
756     }
757
758     private static Object JavaDoc exposed_decl_get_object(Class JavaDoc c, String JavaDoc name) {
759         try {
760             return c.getDeclaredField("exposed_" + name).get(null);
761         } catch (NoSuchFieldException JavaDoc e) {
762             return null;
763         } catch (Exception JavaDoc e) {
764             throw error(e);
765         }
766     }
767
768     private final static String JavaDoc[] EMPTY = new String JavaDoc[0];
769
770     private static PyException error(Exception JavaDoc e) {
771         return Py.JavaError(e);
772     }
773
774     private static Method JavaDoc get_non_static_method(
775         Class JavaDoc c,
776         String JavaDoc name,
777         Class JavaDoc[] parmtypes) {
778         try {
779             Method JavaDoc meth = c.getMethod(name, parmtypes);
780             if (!Modifier.isStatic(meth.getModifiers()))
781                 return meth;
782         } catch (NoSuchMethodException JavaDoc e) {
783         }
784         return null;
785     }
786
787     private static Method JavaDoc get_descr_method(
788         Class JavaDoc c,
789         String JavaDoc name,
790         Class JavaDoc[] parmtypes) {
791         Method JavaDoc meth = get_non_static_method(c, name, parmtypes);
792         if (meth != null && meth.getDeclaringClass() != PyObject.class) {
793             return meth;
794         }
795         return null;
796     }
797
798     private static boolean ignore(Method JavaDoc meth) {
799         Class JavaDoc[] exceptions = meth.getExceptionTypes();
800         for (int j = 0; j < exceptions.length; j++) {
801             if (exceptions[j] == PyIgnoreMethodTag.class) {
802                 return true;
803             }
804         }
805         return false;
806     }
807
808     private final static Class JavaDoc[] O = { PyObject.class };
809     private final static Class JavaDoc[] OO = { PyObject.class, PyObject.class };
810
811     private static void fillFromClass(
812         PyType newtype,
813         String JavaDoc name,
814         Class JavaDoc c,
815         Class JavaDoc base,
816         boolean newstyle,
817         Method JavaDoc setup,
818         String JavaDoc[] exposed_methods) {
819
820         if (base == null) {
821             base = c.getSuperclass();
822         }
823
824         if (name == null) {
825             name = c.getName();
826         }
827
828         if (name.startsWith("org.python.core.Py")) {
829             name = name.substring("org.python.core.Py".length()).toLowerCase();
830         } else {
831             int lastdot = name.lastIndexOf('.');
832             if (lastdot != -1) {
833                 name = name.substring(lastdot+1);
834             }
835         }
836
837         newtype.name = name;
838
839         newtype.underlying_class = c;
840
841         boolean top = false;
842
843         // basic mro, base, bases
844
PyType[] mro = null;
845         if (base == Object JavaDoc.class) {
846             mro = new PyType[] { newtype };
847             top = true;
848         } else {
849             PyType basetype = fromClass(base);
850             mro = new PyType[basetype.mro.length + 1];
851             System.arraycopy(basetype.mro, 0, mro, 1, basetype.mro.length);
852             mro[0] = newtype;
853
854             newtype.base = basetype;
855             newtype.bases = new PyObject[] { basetype };
856         }
857         newtype.mro = mro;
858
859         HashMap JavaDoc propnames = null;
860         if (!newstyle)
861             propnames = new HashMap JavaDoc();
862
863         boolean only_exposed_methods = newstyle;
864
865         PyObject dict = new PyStringMap();
866
867         if (only_exposed_methods) {
868             for (int i = 0; i < exposed_methods.length; i++) {
869                 String JavaDoc methname = exposed_methods[i];
870                 dict.__setitem__(
871                     normalize_name(methname),
872                     new PyReflectedFunction(methname));
873             }
874         }
875
876         Method JavaDoc[] methods = c.getMethods();
877         for (int i = 0; i < methods.length; i++) {
878             Method JavaDoc meth = methods[i];
879
880             Class JavaDoc declaring = meth.getDeclaringClass();
881             if (declaring != base
882                 && base.isAssignableFrom(declaring)
883                 && !ignore(meth)) {
884                 String JavaDoc methname = meth.getName();
885                 String JavaDoc nmethname = normalize_name(methname);
886                 PyReflectedFunction reflfunc =
887                     (PyReflectedFunction) dict.__finditem__(nmethname);
888                 boolean added = false;
889                 if (reflfunc == null) {
890                     if (!only_exposed_methods) {
891                         dict.__setitem__(
892                             nmethname,
893                             new PyReflectedFunction(meth));
894                         added = true;
895                     }
896                 } else {
897                     reflfunc.addMethod(meth);
898                     added = true;
899                 }
900                 if (propnames != null
901                     && added
902                     && !Modifier.isStatic(meth.getModifiers())) {
903                     // check for xxxX.*
904
int n = meth.getParameterTypes().length;
905                     if (methname.startsWith("get") && n == 0) {
906                         propnames.put(methname.substring(3), "getter");
907                     } else if (
908                         methname.startsWith("is")
909                             && n == 0
910                             && meth.getReturnType() == Boolean.TYPE) {
911                         propnames.put(methname.substring(2), "getter");
912                     } else if (methname.startsWith("set") && n == 1) {
913                         propnames.put(methname.substring(3), meth);
914                     }
915                 }
916
917             }
918
919         }
920
921         boolean has_set = false, has_delete = false;
922         if (!top) {
923             if (get_descr_method(c, "__set__", OO) != null || /*backw comp*/
924                 get_descr_method(c, "_doset", OO) != null) {
925                 has_set = true;
926             }
927
928             if (get_descr_method(c, "__delete__", O) != null || /*backw comp*/
929                 get_descr_method(c, "_dodel", O) != null) {
930                 has_delete = true;
931             }
932         }
933
934         for (int i = 0; i < methods.length; i++) {
935             Method JavaDoc meth = methods[i];
936
937             String JavaDoc nmethname = normalize_name(meth.getName());
938             PyReflectedFunction reflfunc =
939                 (PyReflectedFunction) dict.__finditem__(nmethname);
940             if (reflfunc != null) {
941                 reflfunc.addMethod(meth);
942             }
943
944         }
945
946         if (!newstyle) { // backward compatibility
947
Field JavaDoc[] fields = c.getFields();
948
949             for (int i = 0; i < fields.length; i++) {
950                 Field JavaDoc field = fields[i];
951                 Class JavaDoc declaring = field.getDeclaringClass();
952                 if (declaring != base && base.isAssignableFrom(declaring)) {
953                     String JavaDoc fldname = field.getName();
954                     int fldmods = field.getModifiers();
955                     Class JavaDoc fldtype = field.getType();
956                     if (Modifier.isStatic(fldmods)) {
957                         // ignore static PyClass __class__
958
if (fldname.equals("__class__")
959                             && fldtype == PyClass.class) {
960                             continue;
961                         } else if (
962                             fldname.startsWith("__doc__")
963                                 && fldname.length() > 7
964                                 && fldtype == PyString.class) {
965                             String JavaDoc fname = fldname.substring(7).intern();
966                             PyObject memb = dict.__finditem__(fname);
967                             if (memb != null
968                                 && memb instanceof PyReflectedFunction) {
969                                 PyString doc = null;
970                                 try {
971                                     doc = (PyString) field.get(null);
972                                 } catch (IllegalAccessException JavaDoc e) {
973                                     throw error(e);
974                                 }
975                                 ((PyReflectedFunction) memb).__doc__ = doc;
976                             }
977
978                         }
979                     }
980                     dict.__setitem__(
981                         normalize_name(fldname),
982                         new PyReflectedField(field));
983                 }
984
985             }
986
987             for (Iterator JavaDoc iter = propnames.keySet().iterator();
988                 iter.hasNext();
989                 ) {
990                 String JavaDoc propname = (String JavaDoc) iter.next();
991                 String JavaDoc npropname = normalize_name(decapitalize(propname));
992                 PyObject prev = dict.__finditem__(npropname);
993                 if (prev != null && prev instanceof PyReflectedFunction) {
994                     continue;
995                 }
996                 Method JavaDoc getter = null;
997                 Method JavaDoc setter = null;
998                 Class JavaDoc proptype = null;
999                 getter =
1000                    get_non_static_method(c, "get" + propname, new Class JavaDoc[] {
1001                });
1002                if (getter == null)
1003                    getter =
1004                        get_non_static_method(c, "is" + propname, new Class JavaDoc[] {
1005                });
1006                if (getter != null) {
1007                    proptype = getter.getReturnType();
1008                    setter =
1009                        get_non_static_method(
1010                            c,
1011                            "set" + propname,
1012                            new Class JavaDoc[] { proptype });
1013                } else {
1014                    Object JavaDoc o = propnames.get(propname);
1015                    if (o instanceof Method JavaDoc) {
1016                        setter = (Method JavaDoc) o;
1017                        proptype = setter.getParameterTypes()[0];
1018                    }
1019                }
1020                if (setter != null || getter != null) {
1021                    dict.__setitem__(
1022                        npropname,
1023                        new PyBeanProperty(
1024                            npropname,
1025                            proptype,
1026                            getter,
1027                            setter));
1028
1029                } else {
1030                    // xxx error
1031
}
1032            }
1033
1034            Constructor JavaDoc[] ctrs = c.getConstructors();
1035            if (ctrs.length != 0) {
1036                final PyReflectedConstructor reflctr =
1037                    new PyReflectedConstructor("_new_impl");
1038                for (int i = 0; i < ctrs.length; i++) {
1039                    reflctr.addConstructor(ctrs[i]);
1040                }
1041                PyObject new_ = new PyNewWrapper(c, "__new__", -1, -1) {
1042
1043                    public PyObject new_impl(
1044                        boolean init,
1045                        PyType subtype,
1046                        PyObject[] args,
1047                        String JavaDoc[] keywords) {
1048                        return reflctr.make(args, keywords);
1049                    }
1050                };
1051
1052                dict.__setitem__("__new__", new_);
1053            }
1054
1055            if (ClassDictInit.class.isAssignableFrom(c)
1056                && c != ClassDictInit.class) {
1057                try {
1058                    Method JavaDoc m =
1059                        c.getMethod(
1060                            "classDictInit",
1061                            new Class JavaDoc[] { PyObject.class });
1062                    m.invoke(null, new Object JavaDoc[] { dict });
1063                } catch (Exception JavaDoc exc) {
1064                    throw error(exc);
1065                }
1066            }
1067
1068        } else {
1069            if (setup != null) {
1070                try {
1071                    setup.invoke(null, new Object JavaDoc[] { dict, null });
1072                } catch (Exception JavaDoc e) {
1073                    throw error(e);
1074                }
1075            }
1076            newtype.non_instantiable = dict.__finditem__("__new__") == null;
1077
1078        }
1079
1080        newtype.has_set = has_set;
1081        newtype.has_delete = has_delete;
1082        newtype.dict = dict;
1083    }
1084
1085    private static HashMap JavaDoc class_to_type;
1086
1087    public static interface Newstyle {
1088    }
1089
1090    private static PyType addFromClass(Class JavaDoc c) {
1091        Method JavaDoc setup = null;
1092        boolean newstyle = Newstyle.class.isAssignableFrom(c);
1093        Class JavaDoc base = null;
1094        String JavaDoc name = null;
1095        String JavaDoc[] exposed_methods = null;
1096        try {
1097            setup =
1098                c.getDeclaredMethod(
1099                    "typeSetup",
1100                    new Class JavaDoc[] { PyObject.class, Newstyle.class });
1101            newstyle = true;
1102        } catch (NoSuchMethodException JavaDoc e) {
1103        } catch (Exception JavaDoc e) {
1104            throw error(e);
1105        }
1106        if (newstyle) { // newstyle
1107
base = (Class JavaDoc) exposed_decl_get_object(c, "base");
1108            name = (String JavaDoc) exposed_decl_get_object(c, "name");
1109            if (base == null) {
1110                Class JavaDoc cur = c;
1111                while (cur != PyObject.class) {
1112                    Class JavaDoc exposed_as =
1113                        (Class JavaDoc) exposed_decl_get_object(cur, "as");
1114                    if (exposed_as != null) {
1115                        PyType exposed_as_type = fromClass(exposed_as);
1116                        class_to_type.put(c, exposed_as_type);
1117                        return exposed_as_type;
1118                    }
1119                    cur = cur.getSuperclass();
1120                }
1121            }
1122            exposed_methods = (String JavaDoc[]) exposed_decl_get_object(c, "methods");
1123            if (exposed_methods == null)
1124                exposed_methods = EMPTY;
1125        }
1126        PyType newtype = c == PyType.class ? new PyType(true) : new PyType();
1127        class_to_type.put(c, newtype);
1128        fillFromClass(newtype, name, c, base, newstyle, setup, exposed_methods);
1129        return newtype;
1130    }
1131
1132    /*
1133     * considers:
1134     * if c implements Newstyle => c and all subclasses
1135     * are considered newstyle
1136     *
1137     * if c has static typeSetup(PyObject dict, Newstyle marker)
1138     * => c is considired newstyle, subclasses are not automatically;
1139     * typeSetup is invoked to populate dict which will become
1140     * type's __dict__
1141     *
1142     * Class exposed_base
1143     * String exposed_name
1144     *
1145     * Class exposed_as => instances are exposed as implementing
1146     * just this superclass
1147     *
1148     * (String[] exposed_methods)
1149     *
1150     */

1151
1152    public static synchronized PyType fromClass(Class JavaDoc c) {
1153        if (class_to_type == null) {
1154            class_to_type = new HashMap JavaDoc();
1155            addFromClass(PyType.class);
1156        }
1157        PyType type = (PyType) class_to_type.get(c);
1158        if (type != null)
1159            return type;
1160        return addFromClass(c);
1161    }
1162
1163    // name must be interned
1164
final PyObject type___findattr__(String JavaDoc name) {
1165        PyType metatype = getType();
1166
1167        PyObject metaattr = metatype.lookup(name);
1168        PyObject res = null;
1169
1170        if (metaattr != null) {
1171            if (metaattr.isDataDescr()) {
1172                res = metaattr.__get__(this, metatype);
1173                if (res != null)
1174                    return res;
1175            }
1176        }
1177
1178        PyObject attr = lookup(name);
1179
1180        if (attr != null) {
1181            res = attr.__get__(null, this);
1182            if (res != null)
1183                return res;
1184        }
1185
1186        if (metaattr != null) {
1187            return metaattr.__get__(this, metatype);
1188        }
1189
1190        return null;
1191    }
1192
1193    final void type___setattr__(String JavaDoc name, PyObject value) {
1194        super.__setattr__(name, value);
1195        if (name == "__set__") {
1196            if (!has_set && lookup("__set__") != null) {
1197                traverse_hierarchy(false, new OnType() {
1198                    public boolean onType(PyType type) {
1199                        boolean old = type.has_set;
1200                        type.has_set = true;
1201                        return old;
1202                    }
1203                });
1204            }
1205        } else if (name == "__delete__") {
1206            if (!has_delete && lookup("__delete__") != null) {
1207                traverse_hierarchy(false, new OnType() {
1208                    public boolean onType(PyType type) {
1209                        boolean old = type.has_delete;
1210                        type.has_delete = true;
1211                        return old;
1212                    }
1213                });
1214            }
1215        }
1216
1217    }
1218
1219    final void type___delattr__(String JavaDoc name) {
1220        super.__delattr__(name);
1221        if (name == "__set__") {
1222            if (has_set && lookup("__set__") == null) {
1223                traverse_hierarchy(false, new OnType() {
1224                    public boolean onType(PyType type) {
1225                        boolean absent =
1226                            type.getDict().__finditem__("__set__") == null;
1227                        if (absent) {
1228                            type.has_set = false;
1229                            return false;
1230                        }
1231                        return true;
1232                    }
1233                });
1234            }
1235        } else if (name == "__delete__") {
1236            if (has_set && lookup("__delete__") == null) {
1237                traverse_hierarchy(false, new OnType() {
1238                    public boolean onType(PyType type) {
1239                        boolean absent =
1240                            type.getDict().__finditem__("__delete__") == null;
1241                        if (absent) {
1242                            type.has_delete = false;
1243                            return false;
1244                        }
1245                        return true;
1246                    }
1247                });
1248            }
1249        }
1250    }
1251
1252    protected void __rawdir__(PyDictionary accum) {
1253        PyObject[] mro = this.mro;
1254        for (int i = 0; i < mro.length; i++) {
1255            mro[i].addKeys(accum, "__dict__");
1256        }
1257    }
1258
1259    /**
1260     * @see org.python.core.PyObject#fastGetDict()
1261     */

1262    public PyObject fastGetDict() {
1263        return dict;
1264    }
1265
1266
1267    public PyObject getDict() { // xxx return dict-proxy
1268
return dict;
1269    }
1270
1271    public Object JavaDoc __tojava__(Class JavaDoc c) {
1272        if (c == Object JavaDoc.class || c == Class JavaDoc.class || c == Serializable JavaDoc.class) {
1273            return underlying_class;
1274        }
1275        return super.__tojava__(c);
1276    }
1277
1278    public PyObject getModule() {
1279        if (underlying_class != null)
1280            return new PyString("__builtin__");
1281        return dict.__finditem__("__module__");
1282    }
1283
1284    public String JavaDoc getFullName () {
1285        if (underlying_class != null)
1286            return name;
1287        PyObject mod = getModule();
1288        if (mod != null)
1289            return mod.__str__()+"."+name;
1290        return name;
1291    }
1292
1293    public String JavaDoc toString() {
1294        if (underlying_class != null)
1295            return "<type '" + name + "'>";
1296        return "<class '" + getFullName() + "'>";
1297    }
1298
1299    /**
1300     * @see org.python.core.PyObject#__findattr__(java.lang.String)
1301     */

1302    public PyObject __findattr__(String JavaDoc name) {
1303        return type___findattr__(name);
1304    }
1305
1306    /**
1307     * @see org.python.core.PyObject#__delattr__(java.lang.String)
1308     */

1309    public void __delattr__(String JavaDoc name) {
1310        type___delattr__(name);
1311    }
1312
1313    /**
1314     * @see org.python.core.PyObject#__setattr__(java.lang.String, org.python.core.PyObject)
1315     */

1316    public void __setattr__(String JavaDoc name, PyObject value) {
1317         type___setattr__(name, value);
1318    }
1319
1320    /**
1321     * @see org.python.core.PyObject#safeRepr()
1322     */

1323    public String JavaDoc safeRepr() throws PyIgnoreMethodTag {
1324        return "type object '" + name + "'"; // xxx use fullname
1325
}
1326
1327    private static PyObject invoke_new_(PyObject new_,PyType type,boolean init,PyObject[] args,String JavaDoc[] keywords) {
1328        PyObject newobj;
1329        if (new_ instanceof PyNewWrapper) {
1330            newobj = ((PyNewWrapper) new_).new_impl(init, type, args, keywords);
1331        } else {
1332            int n = args.length;
1333            PyObject[] type_prepended = new PyObject[n + 1];
1334            System.arraycopy(args, 0, type_prepended, 1, n);
1335            type_prepended[0] = type;
1336            newobj = new_.__get__(null, type).__call__(type_prepended, keywords);
1337        }
1338        newobj.dispatch__init__(type,args,keywords);
1339        return newobj;
1340    }
1341
1342
1343    /**
1344     * @see org.python.core.PyObject#__call__(org.python.core.PyObject[], java.lang.String[])
1345     */

1346    public PyObject __call__(PyObject[] args, String JavaDoc[] keywords) {
1347        return type___call__(args,keywords);
1348    }
1349
1350    final PyObject type___call__(PyObject[] args, String JavaDoc[] keywords) {
1351        PyObject new_ = lookup("__new__");
1352        if (non_instantiable || new_ == null) {
1353            throw Py.TypeError("cannot create '" + name + "' instances");
1354            // xxx fullname
1355
}
1356
1357        return invoke_new_(new_,this,true,args,keywords);
1358    }
1359
1360}
1361
Popular Tags