package org.python.core;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* first-class Python type.
*
*/
public class PyType extends PyObject implements Serializable {
//~ BEGIN GENERATED REGION -- DO NOT EDIT SEE gexpose.py
/* type info */
public static final String exposed_name = "type";
public static void typeSetup(PyObject dict, PyType.Newstyle marker) {
dict.__setitem__("__dict__", new PyGetSetDescr("__dict__", PyType.class, "getDict", "setDict", "delDict"));
dict.__setitem__("__name__", new PyGetSetDescr("__name__", PyType.class, "fastGetName", null, null));
dict.__setitem__("__base__", new PyGetSetDescr("__base__", PyType.class, "getBase", null, null));
dict.__setitem__("__bases__", new PyGetSetDescr("__bases__", PyType.class, "getBases", "setBases", "delBases"));
dict.__setitem__("__mro__", new PyGetSetDescr("__mro__", PyType.class, "getMro", null, null));
class exposed_mro extends PyBuiltinMethodNarrow {
exposed_mro(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed_mro(self, info);
}
public PyObject __call__(PyObject arg0) {
return ((PyType) self).type_mro(arg0);
}
public PyObject __call__() {
return ((PyType) self).type_mro();
}
}
dict.__setitem__("mro", new PyMethodDescr("mro", PyType.class, 0, 1, new exposed_mro(null, null)));
class exposed___getattribute__ extends PyBuiltinMethodNarrow {
exposed___getattribute__(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed___getattribute__(self, info);
}
public PyObject __call__(PyObject arg0) {
try {
String name = (arg0.asName(0));
PyObject ret = ((PyType) self).type___findattr__(name);
if (ret == null)
((PyType) self).noAttributeError(name);
return ret;
} catch (PyObject.ConversionException e) {
String msg;
switch (e.index) {
case 0:
msg = "attribute name must be a string";
break;
default:
msg = "xxx";
}
throw Py.TypeError(msg);
}
}
}
dict.__setitem__("__getattribute__", new PyMethodDescr("__getattribute__", PyType.class, 1, 1,
new exposed___getattribute__(null, null)));
class exposed___setattr__ extends PyBuiltinMethodNarrow {
exposed___setattr__(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed___setattr__(self, info);
}
public PyObject __call__(PyObject arg0, PyObject arg1) {
try {
((PyType) self).type___setattr__(arg0.asName(0), arg1);
return Py.None;
} catch (PyObject.ConversionException e) {
String msg;
switch (e.index) {
case 0:
msg = "attribute name must be a string";
break;
default:
msg = "xxx";
}
throw Py.TypeError(msg);
}
}
}
dict.__setitem__("__setattr__", new PyMethodDescr("__setattr__", PyType.class, 2, 2, new exposed___setattr__(
null, null)));
class exposed___delattr__ extends PyBuiltinMethodNarrow {
exposed___delattr__(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed___delattr__(self, info);
}
public PyObject __call__(PyObject arg0) {
try {
((PyType) self).type___delattr__(arg0.asName(0));
return Py.None;
} catch (PyObject.ConversionException e) {
String msg;
switch (e.index) {
case 0:
msg = "attribute name must be a string";
break;
default:
msg = "xxx";
}
throw Py.TypeError(msg);
}
}
}
dict.__setitem__("__delattr__", new PyMethodDescr("__delattr__", PyType.class, 1, 1, new exposed___delattr__(
null, null)));
class exposed___subclasses__ extends PyBuiltinMethodNarrow {
exposed___subclasses__(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed___subclasses__(self, info);
}
public PyObject __call__() {
return ((PyType) self).type_getSubclasses();
}
}
dict.__setitem__("__subclasses__", new PyMethodDescr("__subclasses__", PyType.class, 0, 0,
new exposed___subclasses__(null, null)));
class exposed___call__ extends PyBuiltinMethod {
exposed___call__(PyObject self, PyBuiltinFunction.Info info) {
super(self, info);
}
public PyBuiltinFunction bind(PyObject self) {
return new exposed___call__(self, info);
}
public PyObject __call__(PyObject[] args) {
return __call__(args, Py.NoKeywords);
}
public PyObject __call__(PyObject[] args, String[] keywords) {
return ((PyType) self).type___call__(args, keywords);
}
}
dict.__setitem__("__call__", new PyMethodDescr("__call__", PyType.class, -1, -1, new exposed___call__(null,
null)));
dict.__setitem__("__new__", new PyNewWrapper(PyType.class, "__new__", -1, -1) {
public PyObject new_impl(boolean init, PyType subtype, PyObject[] args, String[] keywords) {
return type_new(this, init, subtype, args, keywords);
}
});
}
//~ END GENERATED REGION -- DO NOT EDIT SEE gexpose.py
public static PyObject type_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) {
if (args.length == 1 && keywords.length == 0) {
return args[0].getType();
}
if (args.length + keywords.length != 3)
throw Py.TypeError("type() takes exactly 1 or 3 arguments");
ArgParser ap = new ArgParser("type()", args, keywords, "name", "bases", "dict");
String name = ap.getString(0);
PyObject bases = ap.getPyObject(1);
if (!(bases instanceof PyTuple))
throw Py.TypeError("type(): bases must be tuple");
PyObject dict = ap.getPyObject(2);
if (!(dict instanceof PyDictionary || dict instanceof PyStringMap))
throw Py.TypeError("type(): dict must be dict");
return newType(new_, subtype, name, (PyTuple) bases, dict);
}
private Object writeReplace() {
//System.err.println("replace type");
return new TypeResolver(underlying_class, getModule().toString(), name);
}
static class TypeResolver implements Serializable {
private Class underlying_class;
private String module;
private String name;
TypeResolver(Class underlying_class, String module, String name) {
this.underlying_class = underlying_class;
this.module = module;
this.name = name;
}
private Object readResolve() {
//System.err.println("resolve: "+module+"."+name);
if (underlying_class != null)
return PyType.fromClass(underlying_class);
PyObject mod = imp.importName(module.intern(), false);
PyObject pytyp = mod.__getattr__(name.intern());
if (!(pytyp instanceof PyType)) {
throw Py.TypeError(module + "." + name + " must be a type for deserialization");
}
return (PyType) pytyp;
}
}
public PyObject getStatic() {
PyType cur = this;
while (cur.underlying_class == null) {
cur = cur.base;
}
return cur;
}
/**
* Checks that the physical layout between this type and <code>other</code>
* are compatible.
*/
public boolean layoutAligns(PyType other) {
return getLayout().equals(other.getLayout()) && needs_userdict == other.needs_userdict
&& needs_finalizer == other.needs_finalizer;
}
/**
* Gets the most parent PyType that determines the layout of this type ie
* has slots or an underlying_class. Can by this PyType.
*/
private PyType getLayout() {
if (underlying_class != null) {
return this;
} else if (numSlots != base.numSlots) {
return this;
}
return base.getLayout();
}
public PyObject getBase() {
if (base == null)
return Py.None;
return base;
}
public PyObject getBases() {
if (bases == null)
return new PyTuple();
return new PyTuple(bases);
}
public void delBases() {
throw Py.TypeError("Can't delete __bases__ attribute");
}
public void setBases(PyObject newBasesTuple) {
if (!(newBasesTuple instanceof PyTuple)) {
throw Py.TypeError("bases must be a tuple");
}
PyObject[] newBases = ((PyTuple) newBasesTuple).getArray();
if (newBases.length == 0) {
throw Py.TypeError("can only assign non-empty tuple to __bases__, not " + newBasesTuple);
}
for (int i = 0; i < newBases.length; i++) {
if (!(newBases[i] instanceof PyType)) {
if (!(newBases[i] instanceof PyClass)) {
throw Py.TypeError(name + ".__bases__ must be a tuple of old- or new-style classes, not "
+ newBases[i]);
}
} else {
if (((PyType) newBases[i]).isSubType(this)) {
throw Py.TypeError("a __bases__ item causes an inheritance cycle");
}
}
}
PyType newBase = best_base(newBases);
if (!newBase.layoutAligns(base)) {
throw Py.TypeError("'" + base + "' layout differs from '" + newBase + "'");
}
PyObject[] savedBases = bases;
PyType savedBase = base;
PyObject[] savedMro = mro;
List savedSubMros = new ArrayList();
try {
bases = newBases;
base = newBase;
mro_internal();
mro_subclasses(savedSubMros);
for (int i = 0; i < savedBases.length; i++) {
if (savedBases[i] instanceof PyType) {
((PyType) savedBases[i]).detachSubclass(this);
}
}
for (int i = 0; i < newBases.length; i++) {
if (newBases[i] instanceof PyType) {
((PyType) newBases[i]).attachSubclass(this);
}
}
} catch (PyException t) {
for (Iterator it = savedSubMros.iterator(); it.hasNext();) {
PyType subtype = (PyType) it.next();
PyObject[] subtypeSavedMro = (PyObject[]) it.next();
subtype.mro = subtypeSavedMro;
}
bases = savedBases;
base = savedBase;
mro = savedMro;
throw t;
}
}
private void mro_internal() {
if (getType().underlying_class != PyType.class && getType().lookup("mro") != null) {
mro = Py.make_array(getType().lookup("mro").__get__(null, getType()).__call__(this));
} else {
mro = compute_mro();
}
}
/**
* Collects the subclasses and current mro of this type in currentMroSaver. If
* this type has subclasses C and D, and D has a subclass E current mro saver will equal
* [C, C.__mro__, D, D.__mro__, E, E.__mro__] after this call.
*/
private void mro_subclasses(List mroCollector) {
for (java.util.Iterator iter = subclasses.iterator(); iter.hasNext();) {
java.lang.ref.WeakReference type_ref = (java.lang.ref.WeakReference) iter.next();
PyType subtype = (PyType) type_ref.get();
if (subtype == null)
continue;
mroCollector.add(subtype);
mroCollector.add(subtype.mro);
subtype.mro_internal();
subtype.mro_subclasses(mroCollector);
}
}
public PyObject instDict() {
if (needs_userdict) {
return new PyStringMap();
}
return null;
}
private String name;
private PyType base;
private PyObject[] bases;
private PyObject dict;
private PyObject[] mro = new PyObject[0];
private Class underlying_class;
boolean builtin = false;
private boolean non_instantiable = false;
boolean has_set, has_delete;
private boolean needs_finalizer;
private int numSlots;
private boolean needs_userdict = true;
private java.lang.ref.ReferenceQueue subclasses_refq = new java.lang.ref.ReferenceQueue();
private java.util.HashSet subclasses = new java.util.HashSet();
private void cleanup_subclasses() {
java.lang.ref.Reference ref;
while ((ref = subclasses_refq.poll()) != null) {
subclasses.remove(ref);
}
}
public PyTuple getMro() {
return new PyTuple(mro);
}
public synchronized final PyObject type_getSubclasses() {
PyList result = new PyList();
cleanup_subclasses();
for (java.util.Iterator iter = subclasses.iterator(); iter.hasNext();) {
java.lang.ref.WeakReference type_ref = (java.lang.ref.WeakReference) iter.next();
PyType subtype = (PyType) type_ref.get();
if (subtype == null)
continue;
result.append(subtype);
}
return result;
}
private synchronized void attachSubclass(PyType subtype) {
cleanup_subclasses();
subclasses.add(new java.lang.ref.WeakReference(subtype, subclasses_refq));
}
private synchronized void detachSubclass(PyType subtype) {
cleanup_subclasses();
for (java.util.Iterator iter = subclasses.iterator(); iter.hasNext();) {
java.lang.ref.WeakReference type_ref = (java.lang.ref.WeakReference) iter.next();
PyType refType = (PyType) type_ref.get();
if (refType == subtype) {
subclasses.remove(type_ref);
break;
}
}
}
private interface OnType {
boolean onType(PyType type);
}
private synchronized void traverse_hierarchy(boolean top, OnType behavior) {
boolean stop = false;
if (!top) {
stop = behavior.onType(this);
}
if (stop)
return;
for (java.util.Iterator iter = subclasses.iterator(); iter.hasNext();) {
java.lang.ref.WeakReference type_ref = (java.lang.ref.WeakReference) iter.next();
PyType subtype = (PyType) type_ref.get();
if (subtype == null)
continue;
subtype.traverse_hierarchy(false, behavior);
}
}
private static void fill_classic_mro(ArrayList acc, PyClass classic_cl) {
if (!acc.contains(classic_cl))
acc.add(classic_cl);
PyObject[] bases = classic_cl.__bases__.getArray();
for (int i = 0; i < bases.length; i++) {
fill_classic_mro(acc, (PyClass) bases[i]);
}
}
private static PyObject[] classic_mro(PyClass classic_cl) {
ArrayList acc = new ArrayList();
fill_classic_mro(acc, classic_cl);
return (PyObject[]) acc.toArray(new PyObject[0]);
}
private static boolean tail_contains(PyObject[] lst, int whence, PyObject o) {
int n = lst.length;
for (int i = whence + 1; i < n; i++) {
if (lst[i] == o)
return true;
}
return false;
}
private static PyException mro_error(PyObject[][] to_merge, int[] remain) {
StringBuffer msg = new StringBuffer("Cannot create a" + " consistent method resolution\norder (MRO) for bases ");
PyDictionary set = new PyDictionary();
for (int i = 0; i < to_merge.length; i++) {
PyObject[] lst = to_merge[i];
if (remain[i] < lst.length)
set.__setitem__(lst[remain[i]], Py.None);
}
PyObject iter = set.__iter__();
PyObject cur;
boolean subq = false;
while ((cur = iter.__iternext__()) != null) {
PyObject name = cur.__findattr__("__name__");
if (!subq) {
subq = true;
} else {
msg.append(", ");
}
msg.append(name == null ? "?" : name.toString());
}
return Py.TypeError(msg.toString());
}
private static void debug(PyObject[] objs) {
System.out.println(new PyList(objs).toString());
}
final PyList type_mro() {
return new PyList(compute_mro());
}
final PyList type_mro(PyObject o) {
return ((PyType) o).type_mro();
}
final PyObject[] compute_mro() {
PyObject[] bases = this.bases;
int n = bases.length;
for (int i = 0; i < n; i++) {
PyObject cur = bases[i];
for (int j = i + 1; j < n; j++) {
if (bases[j] == cur) {
PyObject name = cur.__findattr__("__name__");
throw Py.TypeError("duplicate base class " + (name == null ? "?" : name.toString()));
}
}
}
int nmerge = n + 1;
PyObject[][] to_merge = new PyObject[nmerge][];
int[] remain = new int[nmerge];
for (int i = 0; i < n; i++) {
PyObject cur = bases[i];
remain[i] = 0;
if (cur instanceof PyType) {
to_merge[i] = ((PyType) cur).mro;
} else if (cur instanceof PyClass) {
to_merge[i] = classic_mro((PyClass) cur);
}
}
to_merge[n] = bases;
remain[n] = 0;
ArrayList acc = new ArrayList();
acc.add(this);
int empty_cnt = 0;
scan: for (int i = 0; i < nmerge; i++) {
PyObject candidate;
PyObject[] cur = to_merge[i];
if (remain[i] >= cur.length) {
empty_cnt++;
continue scan;
}
candidate = cur[remain[i]];
for (int j = 0; j < nmerge; j++)
if (tail_contains(to_merge[j], remain[j], candidate))
continue scan;
acc.add(candidate);
for (int j = 0; j < nmerge; j++) {
if (remain[j] < to_merge[j].length && to_merge[j][remain[j]] == candidate)
remain[j]++;
}
// restart scan
i = -1;
empty_cnt = 0;
}
if (empty_cnt == nmerge) {
return (PyObject[]) acc.toArray(bases);
}
throw mro_error(to_merge, remain);
}
/**
* Finds the parent of base with an underlying_class or with slots
*
* @raises Py.TypeError if there is no solid base for base
*/
private static PyType solid_base(PyType base) {
PyObject[] mro = base.mro;
for (int i = 0; i < mro.length; i++) {
PyObject parent = mro[i];
if (parent instanceof PyType) {
PyType parent_type = (PyType) parent;
if (isSolidBase(parent_type))
return parent_type;
}
}
throw Py.TypeError("base without solid base");
}
private static boolean isSolidBase(PyType type) {
return type.underlying_class != null || type.numSlots != 0;
}
/**
* Finds the base in bases with the most derived solid_base, ie the most base type
*
* @throws Py.TypeError if the bases don't all derive from the same solid_base
* @throws Py.TypeError if at least one of the bases isn't a new-style class
*/
private static PyType best_base(PyObject[] bases) {
PyType winner = null;
PyType candidate = null;
PyType best = null;
for (int i = 0; i < bases.length; i++) {
PyObject base_proto = bases[i];
if (base_proto instanceof PyClass)
continue;
if (!(base_proto instanceof PyType))
throw Py.TypeError("bases must be types");
PyType base = (PyType) base_proto;
candidate = solid_base(base);
if (winner == null) {
winner = candidate;
best = base;
} else if (winner.isSubType(candidate)) {
;
} else if (candidate.isSubType(winner)) {
winner = candidate;
best = base;
} else {
throw Py.TypeError("multiple bases have instance lay-out conflict");
}
}
if (best == null)
throw Py.TypeError("a new-style class can't have only classic bases");
return best;
}
public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, PyTuple bases, PyObject dict) {
PyType object_type = fromClass(PyObject.class);
PyObject[] bases_list = bases.getArray();
PyType winner = findMostDerivedMetatype(bases_list, metatype);
if (winner != metatype) {
PyObject winner_new_ = winner.lookup("__new__");
if (winner_new_ != null && winner_new_ != new_) {
return invoke_new_(new_, winner, false, new PyObject[] { new PyString(name), bases, dict },
Py.NoKeywords);
}
metatype = winner;
}
if (bases_list.length == 0) {
bases_list = new PyObject[] { object_type };
}
// xxx can be subclassed ?
if (dict.__finditem__("__module__") == null) {
PyFrame frame = Py.getFrame();
if (frame != null) {
PyObject globals = frame.f_globals;
PyObject modname;
if ((modname = globals.__finditem__("__name__")) != null) {
dict.__setitem__("__module__", modname);
}
}
}
// xxx also __doc__ __module__
PyType newtype;
if (new_.for_type == metatype) {
newtype = new PyType(); // xxx set metatype
} else {
newtype = new PyTypeDerived(metatype);
}
newtype.dict = dict;
newtype.name = name;
newtype.base = best_base(bases_list);
newtype.numSlots = newtype.base.numSlots;
newtype.bases = bases_list;
PyObject slots = dict.__finditem__("__slots__");
if (slots != null) {
newtype.needs_userdict = false;
if (slots instanceof PyString) {
addSlot(newtype, slots);
} else {
PyObject iter = slots.__iter__();
PyObject slotname;
for (; (slotname = iter.__iternext__()) != null;) {
addSlot(newtype, slotname);
}
}
}
if (!newtype.needs_userdict) {
newtype.needs_userdict = necessitatesUserdict(bases_list);
}
// special case __new__, if function => static method
PyObject tmp = dict.__finditem__("__new__");
if (tmp != null && tmp instanceof PyFunction) { // xxx java functions?
dict.__setitem__("__new__", new PyStaticMethod(tmp));
}
newtype.mro_internal();
// __dict__ descriptor
if (newtype.needs_userdict && newtype.lookup("__dict__") == null) {
dict.__setitem__("__dict__", new PyGetSetDescr(newtype, "__dict__", PyObject.class, "getDict", "setDict",
"delDict"));
}
newtype.has_set = newtype.lookup("__set__") != null;
newtype.has_delete = newtype.lookup("__delete__") != null;
newtype.needs_finalizer = newtype.lookup("__del__") != null;
for (int i = 0; i < bases_list.length; i++) {
PyObject cur = bases_list[i];
if (cur instanceof PyType)
((PyType) cur).attachSubclass(newtype);
}
return newtype;
}
private static boolean necessitatesUserdict(PyObject[] bases_list) {
for (int i = 0; i < bases_list.length; i++) {
PyObject cur = bases_list[i];
if ((cur instanceof PyType && ((PyType) cur).needs_userdict && ((PyType) cur).numSlots > 0)
|| cur instanceof PyClass) {
return true;
}
}
return false;
}
/**
* Finds the most derived subtype of initialMetatype in the types of bases, or initialMetatype if
* it is already the most derived.
*
* @raises Py.TypeError if the all the metaclasses don't descend from the same base
* @raises Py.TypeError if one of the bases is a PyJavaClass or a PyClass with no proxyClass
*/
private static PyType findMostDerivedMetatype(PyObject[] bases_list, PyType initialMetatype) {
PyType winner = initialMetatype;
for (int i = 0; i < bases_list.length; i++) {
PyObject bases_i = bases_list[i];
if (bases_i instanceof PyJavaClass)
throw Py.TypeError("can't mix new-style and java classes");
if (bases_i instanceof PyClass) {
if (((PyClass) bases_i).proxyClass != null)
throw Py.TypeError("can't mix new-style and java classes");
continue;
}
PyType curtype = bases_i.getType();
if (winner.isSubType(curtype))
continue;
if (curtype.isSubType(winner)) {
winner = curtype;
continue;
}
throw Py.TypeError("metaclass conflict: " + "the metaclass of a derived class "
+ "must be a (non-strict) subclass " + "of the metaclasses of all its bases");
}
return winner;
}
private static void addSlot(PyType newtype, PyObject slotname) {
confirmIdentifier(slotname);
String slotstring = mangleName(newtype.name, slotname.toString());
if (slotstring.equals("__dict__")) {
newtype.needs_userdict = true;
} else {
newtype.dict.__setitem__(slotstring, new PySlot(newtype, slotstring, newtype.numSlots++));
}
}
public String fastGetName() {
return name;
}
public boolean isSubType(PyType supertype) {
PyObject[] mro = this.mro;
for (int i = 0; i < mro.length; i++) {
if (mro[i] == supertype)
return true;
}
return false;
}
/**
* INTERNAL lookup for name through mro objects' dicts
*
* @param name
* attribute name (must be interned)
* @return found object or null
*/
public PyObject lookup(String name) {
PyObject[] mro = this.mro;
for (int i = 0; i < mro.length; i++) {
PyObject dict = mro[i].fastGetDict();
if (dict != null) {
PyObject obj = dict.__finditem__(name);
if (obj != null)
return obj;
}
}
return null;
}
public PyObject lookup_where(String name, PyObject[] where) {
PyObject[] mro = this.mro;
for (int i = 0; i < mro.length; i++) {
PyObject t = mro[i];
PyObject dict = t.fastGetDict();
if (dict != null) {
PyObject obj = dict.__finditem__(name);
if (obj != null) {
where[0] = t;
return obj;
}
}
}
return null;
}
public PyObject super_lookup(PyType ref, String name) {
PyObject[] mro = this.mro;
int i;
for (i = 0; i < mro.length; i++) {
if (mro[i] == ref)
break;
}
i++;
for (; i < mro.length; i++) {
PyObject dict = mro[i].fastGetDict();
if (dict != null) {
PyObject obj = dict.__finditem__(name);
if (obj != null)
return obj;
}
}
return null;
}
private PyType(boolean dummy) {
super(true);
}
private PyType() {
}
PyType(PyType subtype) {
super(subtype);
}
private static String decapitalize(String s) {
char c0 = s.charAt(0);
if (Character.isUpperCase(c0)) {
if (s.length() > 1 && Character.isUpperCase(s.charAt(1)))
return s;
char[] cs = s.toCharArray();
cs[0] = Character.toLowerCase(c0);
return new String(cs);
} else {
return s;
}
}
private static String normalize_name(String name) {
if (name.endsWith("$"))
name = name.substring(0, name.length() - 1);
return name.intern();
}
private static Object exposed_decl_get_object(Class c, String name) {
try {
return c.getDeclaredField("exposed_" + name).get(null);
} catch (NoSuchFieldException e) {
return null;
} catch (Exception e) {
throw error(e);
}
}
private final static String[] EMPTY = new String[0];
private static PyException error(Exception e) {
return Py.JavaError(e);
}
private static Method get_non_static_method(Class c, String name, Class[] parmtypes) {
try {
Method meth = c.getMethod(name, parmtypes);
if (!Modifier.isStatic(meth.getModifiers()))
return meth;
} catch (NoSuchMethodException e) {
}
return null;
}
private static Method get_descr_method(Class c, String name, Class[] parmtypes) {
Method meth = get_non_static_method(c, name, parmtypes);
if (meth != null && meth.getDeclaringClass() != PyObject.class) {
return meth;
}
return null;
}
private static boolean ignore(Method meth) {
Class[] exceptions = meth.getExceptionTypes();
for (int j = 0; j < exceptions.length; j++) {
if (exceptions[j] == PyIgnoreMethodTag.class) {
return true;
}
}
return false;
}
private final static Class[] O = { PyObject.class };
private final static Class[] OO = { PyObject.class, PyObject.class };
private static void fillFromClass(PyType newtype, String name, Class c, Class base, boolean newstyle, Method setup,
String[] exposed_methods) {
if (base == null) {
base = c.getSuperclass();
}
if (name == null) {
name = c.getName();
}
if (name.startsWith("org.python.core.Py")) {
name = name.substring("org.python.core.Py".length()).toLowerCase();
} else {
int lastdot = name.lastIndexOf('.');
if (lastdot != -1) {
name = name.substring(lastdot + 1);
}
}
newtype.name = name;
newtype.underlying_class = c;
newtype.builtin = true;
boolean top = false;
// basic mro, base, bases
PyType[] mro = null;
if (base == Object.class) {
mro = new PyType[] { newtype };
top = true;
} else {
PyType basetype = fromClass(base);
mro = new PyType[basetype.mro.length + 1];
System.arraycopy(basetype.mro, 0, mro, 1, basetype.mro.length);
mro[0] = newtype;
newtype.base = basetype;
newtype.bases = new PyObject[] { basetype };
}
newtype.mro = mro;
PyObject dict = new PyStringMap();
if (newstyle) {
fillInNewstyle(newtype, setup, exposed_methods, dict);
} else {
fillInClassic(c, base, dict);
}
boolean has_set = false, has_delete = false;
if (!top) {
if (get_descr_method(c, "__set__", OO) != null || /* backw comp */
get_descr_method(c, "_doset", OO) != null) {
has_set = true;
}
if (get_descr_method(c, "__delete__", O) != null || /* backw comp */
get_descr_method(c, "_dodel", O) != null) {
has_delete = true;
}
}
newtype.has_set = has_set;
newtype.has_delete = has_delete;
newtype.dict = dict;
}
private static void fillInClassic(Class c, Class base, PyObject dict) {
HashMap propnames = new HashMap();
Method[] methods = c.getMethods();
for (int i = 0; i < methods.length; i++) {
Method meth = methods[i];
Class declaring = meth.getDeclaringClass();
if (declaring != base && base.isAssignableFrom(declaring) && !ignore(meth)) {
String methname = meth.getName();
String nmethname = normalize_name(methname);
PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname);
boolean added = false;
if (reflfunc == null) {
dict.__setitem__(nmethname, new PyReflectedFunction(meth));
added = true;
} else {
reflfunc.addMethod(meth);
added = true;
}
if (added && !Modifier.isStatic(meth.getModifiers())) {
// check for xxxX.*
int n = meth.getParameterTypes().length;
if (methname.startsWith("get") && n == 0) {
propnames.put(methname.substring(3), "getter");
} else if (methname.startsWith("is") && n == 0 && meth.getReturnType() == Boolean.TYPE) {
propnames.put(methname.substring(2), "getter");
} else if (methname.startsWith("set") && n == 1) {
propnames.put(methname.substring(3), meth);
}
}
}
}
for (int i = 0; i < methods.length; i++) {
Method meth = methods[i];
String nmethname = normalize_name(meth.getName());
PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname);
if (reflfunc != null) {
reflfunc.addMethod(meth);
}
}
Field[] fields = c.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class declaring = field.getDeclaringClass();
if (declaring != base && base.isAssignableFrom(declaring)) {
String fldname = field.getName();
int fldmods = field.getModifiers();
Class fldtype = field.getType();
if (Modifier.isStatic(fldmods)) {
// ignore static PyClass __class__
if (fldname.equals("__class__") && fldtype == PyClass.class) {
continue;
} else if (fldname.startsWith("__doc__") && fldname.length() > 7 && fldtype == PyString.class) {
String fname = fldname.substring(7).intern();
PyObject memb = dict.__finditem__(fname);
if (memb != null && memb instanceof PyReflectedFunction) {
PyString doc = null;
try {
doc = (PyString) field.get(null);
} catch (IllegalAccessException e) {
throw error(e);
}
((PyReflectedFunction) memb).__doc__ = doc;
}
}
}
dict.__setitem__(normalize_name(fldname), new PyReflectedField(field));
}
}
for (Iterator iter = propnames.keySet().iterator(); iter.hasNext();) {
String propname = (String) iter.next();
String npropname = normalize_name(decapitalize(propname));
PyObject prev = dict.__finditem__(npropname);
if (prev != null && prev instanceof PyReflectedFunction) {
continue;
}
Method getter = null;
Method setter = null;
Class proptype = null;
getter = get_non_static_method(c, "get" + propname, new Class[] {});
if (getter == null)
getter = get_non_static_method(c, "is" + propname, new Class[] {});
if (getter != null) {
proptype = getter.getReturnType();
setter = get_non_static_method(c, "set" + propname, new Class[] { proptype });
} else {
Object o = propnames.get(propname);
if (o instanceof Method) {
setter = (Method) o;
proptype = setter.getParameterTypes()[0];
}
}
if (setter != null || getter != null) {
dict.__setitem__(npropname, new PyBeanProperty(npropname, proptype, getter, setter));
} else {
// xxx error
}
}
Constructor[] ctrs = c.getConstructors();
if (ctrs.length != 0) {
final PyReflectedConstructor reflctr = new PyReflectedConstructor("_new_impl");
for (int i = 0; i < ctrs.length; i++) {
reflctr.addConstructor(ctrs[i]);
}
PyObject new_ = new PyNewWrapper(c, "__new__", -1, -1) {
public PyObject new_impl(boolean init, PyType subtype, PyObject[] args, String[] keywords) {
return reflctr.make(args, keywords);
}
};
dict.__setitem__("__new__", new_);
}
if (ClassDictInit.class.isAssignableFrom(c) && c != ClassDictInit.class) {
try {
Method m = c.getMethod("classDictInit", new Class[] { PyObject.class });
m.invoke(null, new Object[] { dict });
} catch (Exception exc) {
throw error(exc);
}
}
}
private static void fillInNewstyle(PyType newtype, Method setup, String[] exposed_methods, PyObject dict) {
for (int i = 0; i < exposed_methods.length; i++) {
String methname = exposed_methods[i];
dict.__setitem__(normalize_name(methname), new PyReflectedFunction(methname));
}
if (setup != null) {
try {
setup.invoke(null, new Object[] { dict, null });
} catch (Exception e) {
throw error(e);
}
}
newtype.non_instantiable = dict.__finditem__("__new__") == null;
}
private static HashMap class_to_type;
public static interface Newstyle {
}
private static PyType addFromClass(Class c) {
Method setup = null;
boolean newstyle = Newstyle.class.isAssignableFrom(c);
Class base = null;
String name = null;
String[] exposed_methods = null;
try {
setup = c.getDeclaredMethod("typeSetup", new Class[] { PyObject.class, Newstyle.class });
newstyle = true;
} catch (NoSuchMethodException e) {
} catch (Exception e) {
throw error(e);
}
if (newstyle) { // newstyle
base = (Class) exposed_decl_get_object(c, "base");
name = (String) exposed_decl_get_object(c, "name");
if (base == null) {
Class cur = c;
while (cur != PyObject.class) {
Class exposed_as = (Class) exposed_decl_get_object(cur, "as");
if (exposed_as != null) {
PyType exposed_as_type = fromClass(exposed_as);
class_to_type.put(c, exposed_as_type);
return exposed_as_type;
}
cur = cur.getSuperclass();
}
}
exposed_methods = (String[]) exposed_decl_get_object(c, "methods");
if (exposed_methods == null)
exposed_methods = EMPTY;
}
PyType newtype = (PyType) class_to_type.get(c);
if (newtype == null) {
newtype = c == PyType.class ? new PyType(true) : new PyType();
class_to_type.put(c, newtype);
fillFromClass(newtype, name, c, base, newstyle, setup, exposed_methods);
}
return newtype;
}
static PyType TypeType = fromClass(PyType.class);
/*
* considers:
* if c implements Newstyle => c and all subclasses
* are considered newstyle
*
* if c has static typeSetup(PyObject dict, Newstyle marker)
* => c is considired newstyle, subclasses are not automatically;
* typeSetup is invoked to populate dict which will become
* type's __dict__
*
* Class exposed_base
* String exposed_name
*
* Class exposed_as => instances are exposed as implementing
* just this superclass
*
* (String[] exposed_methods)
*
*/
public static synchronized PyType fromClass(Class c) {
if (class_to_type == null) {
class_to_type = new HashMap();
addFromClass(PyType.class);
}
PyType type = (PyType) class_to_type.get(c);
if (type != null)
return type;
return addFromClass(c);
}
// name must be interned
final PyObject type___findattr__(String name) {
PyType metatype = getType();
PyObject metaattr = metatype.lookup(name);
PyObject res = null;
if (metaattr != null) {
if (metaattr.isDataDescr()) {
res = metaattr.__get__(this, metatype);
if (res != null)
return res;
}
}
PyObject attr = lookup(name);
if (attr != null) {
res = attr.__get__(null, this);
if (res != null)
return res;
}
if (metaattr != null) {
return metaattr.__get__(this, metatype);
}
return null;
}
final void type___setattr__(String name, PyObject value) {
super.__setattr__(name, value);
if (name == "__set__") {
if (!has_set && lookup("__set__") != null) {
traverse_hierarchy(false, new OnType() {
public boolean onType(PyType type) {
boolean old = type.has_set;
type.has_set = true;
return old;
}
});
}
} else if (name == "__delete__") {
if (!has_delete && lookup("__delete__") != null) {
traverse_hierarchy(false, new OnType() {
public boolean onType(PyType type) {
boolean old = type.has_delete;
type.has_delete = true;
return old;
}
});
}
}
}
final void type___delattr__(String name) {
super.__delattr__(name);
if (name == "__set__") {
if (has_set && lookup("__set__") == null) {
traverse_hierarchy(false, new OnType() {
public boolean onType(PyType type) {
boolean absent = type.getDict().__finditem__("__set__") == null;
if (absent) {
type.has_set = false;
return false;
}
return true;
}
});
}
} else if (name == "__delete__") {
if (has_set && lookup("__delete__") == null) {
traverse_hierarchy(false, new OnType() {
public boolean onType(PyType type) {
boolean absent = type.getDict().__finditem__("__delete__") == null;
if (absent) {
type.has_delete = false;
return false;
}
return true;
}
});
}
}
}
protected void __rawdir__(PyDictionary accum) {
PyObject[] mro = this.mro;
for (int i = 0; i < mro.length; i++) {
mro[i].addKeys(accum, "__dict__");
}
}
/**
* @see org.python.core.PyObject#fastGetDict()
*/
public PyObject fastGetDict() {
return dict;
}
public PyObject getDict() { // xxx return dict-proxy
return dict;
}
public void setDict(PyObject newDict) {
throw Py.TypeError("can't set attribute '__dict__' of type '" + name + "'");
}
public void delDict() {
throw Py.TypeError("can't delete attribute '__dict__' of type '" + name + "'");
}
public Object __tojava__(Class c) {
if (underlying_class != null && (c == Object.class || c == Class.class || c == Serializable.class)) {
return underlying_class;
}
return super.__tojava__(c);
}
public PyObject getModule() {
if (underlying_class != null)
return new PyString("__builtin__");
return dict.__finditem__("__module__");
}
public int getNumSlots() {
return numSlots;
}
public String getFullName() {
if (underlying_class != null)
return name;
PyObject mod = getModule();
if (mod != null)
return mod.__str__() + "." + name;
return name;
}
public String toString() {
if (underlying_class != null)
return "<type '" + name + "'>";
return "<class '" + getFullName() + "'>";
}
/**
* @see org.python.core.PyObject#__findattr__(java.lang.String)
*/
public PyObject __findattr__(String name) {
return type___findattr__(name);
}
/**
* @see org.python.core.PyObject#__delattr__(java.lang.String)
*/
public void __delattr__(String name) {
type___delattr__(name);
}
/**
* @see org.python.core.PyObject#__setattr__(java.lang.String, org.python.core.PyObject)
*/
public void __setattr__(String name, PyObject value) {
type___setattr__(name, value);
}
/**
* @see org.python.core.PyObject#safeRepr()
*/
public String safeRepr() throws PyIgnoreMethodTag {
return "type object '" + name + "'"; // xxx use fullname
}
private static PyObject invoke_new_(PyObject new_, PyType type, boolean init, PyObject[] args, String[] keywords) {
PyObject newobj;
if (new_ instanceof PyNewWrapper) {
newobj = ((PyNewWrapper) new_).new_impl(init, type, args, keywords);
} else {
int n = args.length;
PyObject[] type_prepended = new PyObject[n + 1];
System.arraycopy(args, 0, type_prepended, 1, n);
type_prepended[0] = type;
newobj = new_.__get__(null, type).__call__(type_prepended, keywords);
}
/* special case type(x) */
if (type == TypeType && args.length == 1 && keywords.length == 0) {
return newobj;
}
newobj.dispatch__init__(type, args, keywords);
return newobj;
}
/**
* @see org.python.core.PyObject#__call__(org.python.core.PyObject[], java.lang.String[])
*/
public PyObject __call__(PyObject[] args, String[] keywords) {
return type___call__(args, keywords);
}
final PyObject type___call__(PyObject[] args, String[] keywords) {
PyObject new_ = lookup("__new__");
if (non_instantiable || new_ == null) {
throw Py.TypeError("cannot create '" + name + "' instances");
// xxx fullname
}
return invoke_new_(new_, this, true, args, keywords);
}
//XXX: consider pulling this out into a generally accessible place
// I bet this is duplicated more or less in other places.
private static void confirmIdentifier(PyObject o) {
String msg = "__slots__ must be identifiers";
if (o == Py.None) {
throw Py.TypeError(msg);
}
String identifier = o.toString();
if (identifier == null || identifier.length() < 1
|| (!Character.isLetter(identifier.charAt(0)) && identifier.charAt(0) != '_')) {
throw Py.TypeError(msg);
}
char[] chars = identifier.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (!Character.isLetterOrDigit(chars[i]) && chars[i] != '_') {
throw Py.TypeError(msg);
}
}
}
//XXX: copied from CodeCompiler.java and changed variable names.
// Maybe this should go someplace for all classes to use.
private static String mangleName(String classname, String methodname) {
if (classname != null && methodname.startsWith("__") && !methodname.endsWith("__")) {
//remove leading '_' from classname
int i = 0;
while (classname.charAt(i) == '_')
i++;
return ("_" + classname.substring(i) + methodname).intern();
}
return methodname;
}
}