-
-
#
# Pyrex - Types
#
def cast_code(self, expr_code):
return "((%s)%s)" % (self.declaration_code(""), expr_code)
-
+
def specialization_name(self):
return self.declaration_code("").replace(" ", "__")
-
+
def base_declaration_code(self, base_code, entity_code):
if entity_code:
return "%s %s" % (base_code, entity_code)
# is_typedef boolean Is a typedef type
# is_string boolean Is a C char * type
# is_unicode boolean Is a UTF-8 encoded C char * type
+ # is_unicode_char boolean Is either Py_UCS4 or Py_UNICODE
# is_returncode boolean Is used only to signal exceptions
# is_error boolean Is the dummy error type
# is_buffer boolean Is buffer access type
# has_attributes boolean Has C dot-selectable attributes
# default_value string Initial value
#
- # declaration_code(entity_code,
+ # declaration_code(entity_code,
# for_display = 0, dll_linkage = None, pyrex = 0)
# Returns a code fragment for the declaration of an entity
# of this type, given a code fragment for the entity.
# Coerces array type into pointer type for use as
# a formal argument type.
#
-
+
is_pyobject = 0
is_unspecified = 0
is_extension_type = 0
is_typedef = 0
is_string = 0
is_unicode = 0
+ is_unicode_char = 0
is_returncode = 0
is_error = 0
is_buffer = 0
has_attributes = 0
default_value = ""
-
+
def resolve(self):
# If a typedef, returns the base type.
return self
-
+
def specialize(self, values):
# TODO(danilo): Override wherever it makes sense.
return self
-
+
def literal_code(self, value):
# Returns a C code fragment representing a literal
# value of this type.
return str(value)
-
+
def __str__(self):
return self.declaration_code("", for_display = 1).strip()
-
+
def same_as(self, other_type, **kwds):
return self.same_as_resolved_type(other_type.resolve(), **kwds)
-
+
def same_as_resolved_type(self, other_type):
return self == other_type or other_type is error_type
-
+
def subtype_of(self, other_type):
return self.subtype_of_resolved_type(other_type.resolve())
-
+
def subtype_of_resolved_type(self, other_type):
return self.same_as(other_type)
-
+
def assignable_from(self, src_type):
return self.assignable_from_resolved_type(src_type.resolve())
-
+
def assignable_from_resolved_type(self, src_type):
return self.same_as(src_type)
-
+
def as_argument_type(self):
return self
-
+
def is_complete(self):
# A type is incomplete if it is an unsized array,
# a struct whose attributes are not defined, etc.
return 1
+def public_decl(base_code, dll_linkage):
+ if dll_linkage:
+ return "%s(%s)" % (dll_linkage, base_code)
+ else:
+ return base_code
+
def create_typedef_type(name, base_type, cname, is_external=0):
if base_type.is_complex:
if is_external:
else:
return CTypedefType(name, base_type, cname, is_external)
+
class CTypedefType(BaseType):
#
# Pseudo-type defined with a ctypedef statement in a
# typedef_cname string
# typedef_base_type PyrexType
# typedef_is_external bool
-
+
is_typedef = 1
typedef_is_external = 0
to_py_utility_code = None
from_py_utility_code = None
-
-
+
+
def __init__(self, name, base_type, cname, is_external=0):
assert not base_type.is_complex
self.typedef_name = name
self.typedef_cname = cname
self.typedef_base_type = base_type
self.typedef_is_external = is_external
-
+
def resolve(self):
return self.typedef_base_type.resolve()
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.typedef_name
else:
base_code = public_decl(self.typedef_cname, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
-
+
def as_argument_type(self):
return self
def cast_code(self, expr_code):
# If self is really an array (rather than pointer), we can't cast.
- # For example, the gmp mpz_t.
+ # For example, the gmp mpz_t.
if self.typedef_base_type.is_array:
base_type = self.typedef_base_type.base_type
return CPtrType(base_type).cast_code(expr_code)
def __repr__(self):
return "<CTypedefType %s>" % self.typedef_cname
-
+
def __str__(self):
return self.typedef_name
def _create_utility_code(self, template_utility_code,
template_function_name):
- type_name = self.typedef_cname.replace(" ","_")
+ type_name = self.typedef_cname.replace(" ","_").replace("::","__")
utility_code = template_utility_code.specialize(
type = self.typedef_cname,
TypeName = type_name)
if self.typedef_is_external:
if not self.to_py_utility_code:
base_type = self.typedef_base_type
- if base_type.is_int:
+ if type(base_type) is CIntType:
+ # Various subclasses have special methods
+ # that should be inherited.
self.to_py_utility_code, self.to_py_function = \
self._create_utility_code(c_typedef_int_to_py_function,
'__Pyx_PyInt_to_py_%s')
if self.typedef_is_external:
if not self.from_py_utility_code:
base_type = self.typedef_base_type
- if base_type.is_int:
+ if type(base_type) is CIntType:
+ # Various subclasses have special methods
+ # that should be inherited.
self.from_py_utility_code, self.from_py_function = \
self._create_utility_code(c_typedef_int_from_py_function,
'__Pyx_PyInt_from_py_%s')
def __getattr__(self, name):
return getattr(self.typedef_base_type, name)
+
class BufferType(BaseType):
#
# Delegates most attribute
# lookups to the base type. ANYTHING NOT DEFINED
# HERE IS DELEGATED!
-
+
# dtype PyrexType
# ndim int
# mode str
self.mode = mode
self.negative_indices = negative_indices
self.cast = cast
-
+
def as_argument_type(self):
return self
def __repr__(self):
return "<BufferType %r>" % self.base
-def public_decl(base, dll_linkage):
- if dll_linkage:
- return "%s(%s)" % (dll_linkage, base)
- else:
- return base
-
+
class PyObjectType(PyrexType):
#
# Base class for all Python object types (reference-counted).
buffer_defaults = None
is_extern = False
is_subclassed = False
-
+
def __str__(self):
return "Python object"
-
+
def __repr__(self):
return "<PyObjectType>"
def can_coerce_to_pyobject(self, env):
return True
+ def default_coerced_ctype(self):
+ "The default C type that this Python type coerces to, or None."
+ return None
+
def assignable_from(self, src_type):
# except for pointers, conversion will be attempted
return not src_type.is_ptr or src_type.is_string
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
- return self.base_declaration_code("object", entity_code)
+ base_code = "object"
else:
- return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code)
+ base_code = public_decl("PyObject", dll_linkage)
+ entity_code = "*%s" % entity_code
+ return self.base_declaration_code(base_code, entity_code)
def as_pyobject(self, cname):
if (not self.is_complete()) or self.is_extension_type:
return cname
class BuiltinObjectType(PyObjectType):
+ # objstruct_cname string Name of PyObject struct
is_builtin_type = 1
has_attributes = 1
base_type = None
module_name = '__builtin__'
- alternative_name = None # used for str/bytes duality
+ # fields that let it look like an extension type
+ vtabslot_cname = None
+ vtabstruct_cname = None
+ vtabptr_cname = None
+ typedef_flag = True
+ is_external = True
- def __init__(self, name, cname):
+ def __init__(self, name, cname, objstruct_cname=None):
self.name = name
- if name == 'str':
- self.alternative_name = 'bytes'
- elif name == 'bytes':
- self.alternative_name = 'str'
self.cname = cname
- self.typeptr_cname = "&" + cname
-
+ self.typeptr_cname = "(&%s)" % cname
+ self.objstruct_cname = objstruct_cname
+
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
-
+
def __str__(self):
return "%s object" % self.name
-
+
def __repr__(self):
return "<%s>"% self.cname
-
+
+ def default_coerced_ctype(self):
+ if self.name == 'bytes':
+ return c_char_ptr_type
+ elif self.name == 'bool':
+ return c_bint_type
+ elif self.name == 'float':
+ return c_double_type
+ return None
+
def assignable_from(self, src_type):
if isinstance(src_type, BuiltinObjectType):
- return src_type.name == self.name or (
- src_type.name == self.alternative_name and
- src_type.name is not None)
+ return src_type.name == self.name
elif src_type.is_extension_type:
return (src_type.module_name == '__builtin__' and
src_type.name == self.name)
else:
return True
-
+
def typeobj_is_available(self):
return True
-
+
def attributes_known(self):
return True
-
+
def subtype_of(self, type):
return type.is_pyobject and self.assignable_from(type)
-
- def type_test_code(self, arg, notnone=False):
+
+ def type_check_function(self, exact=True):
type_name = self.name
if type_name == 'str':
- type_check = 'PyString_CheckExact'
- elif type_name == 'set':
- type_check = 'PyAnySet_CheckExact'
+ type_check = 'PyString_Check'
elif type_name == 'frozenset':
- type_check = 'PyFrozenSet_CheckExact'
- elif type_name == 'bool':
- type_check = 'PyBool_Check'
+ type_check = 'PyFrozenSet_Check'
else:
- type_check = 'Py%s_CheckExact' % type_name.capitalize()
+ type_check = 'Py%s_Check' % type_name.capitalize()
+ if exact and type_name not in ('bool', 'slice'):
+ type_check += 'Exact'
+ return type_check
+ def isinstance_code(self, arg):
+ return '%s(%s)' % (self.type_check_function(exact=False), arg)
+
+ def type_test_code(self, arg, notnone=False):
+ type_check = self.type_check_function(exact=True)
check = 'likely(%s(%s))' % (type_check, arg)
if not notnone:
check = check + ('||((%s) == Py_None)' % arg)
error = '(PyErr_Format(PyExc_TypeError, "Expected %s, got %%.200s", Py_TYPE(%s)->tp_name), 0)' % (self.name, arg)
return check + '||' + error
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
- return self.base_declaration_code(self.name, entity_code)
+ base_code = self.name
else:
- return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code)
+ base_code = public_decl("PyObject", dll_linkage)
+ entity_code = "*%s" % entity_code
+ return self.base_declaration_code(base_code, entity_code)
+
+ def cast_code(self, expr_code, to_object_struct = False):
+ return "((%s*)%s)" % (
+ to_object_struct and self.objstruct_cname or "PyObject", # self.objstruct_cname may be None
+ expr_code)
class PyExtensionType(PyObjectType):
# vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition
-
+
is_extension_type = 1
has_attributes = 1
-
+
objtypedef_cname = None
-
+
def __init__(self, name, typedef_flag, base_type, is_external=0):
self.name = name
self.scope = None
self.vtabptr_cname = None
self.vtable_cname = None
self.is_external = is_external
-
+
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
-
+
def subtype_of_resolved_type(self, other_type):
if other_type.is_extension_type:
return self is other_type or (
self.base_type and self.base_type.subtype_of(other_type))
else:
return other_type is py_object_type
-
+
def typeobj_is_available(self):
# Do we have a pointer to the type object?
return self.typeptr_cname
-
+
def typeobj_is_imported(self):
# If we don't know the C name of the type object but we do
# know which module it's defined in, it will be imported.
return self.typeobj_cname is None and self.module_name is not None
-
+
def assignable_from(self, src_type):
if self == src_type:
return True
return self.assignable_from(src_type.base_type)
return False
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0, deref = 0):
if pyrex or for_display:
- return self.base_declaration_code(self.name, entity_code)
+ base_code = self.name
else:
if self.typedef_flag:
objstruct = self.objstruct_cname
else:
objstruct = "struct %s" % self.objstruct_cname
- base = public_decl(objstruct, dll_linkage)
+ base_code = public_decl(objstruct, dll_linkage)
if deref:
- return "%s %s" % (base, entity_code)
+ assert not entity_code
else:
- return "%s *%s" % (base, entity_code)
+ entity_code = "*%s" % entity_code
+ return self.base_declaration_code(base_code, entity_code)
def type_test_code(self, py_arg, notnone=False):
def attributes_known(self):
return self.scope is not None
-
+
def __str__(self):
return self.name
-
+
def __repr__(self):
return "<PyExtensionType %s%s>" % (self.scope.class_name,
("", " typedef")[self.typedef_flag])
-
+
class CType(PyrexType):
#
# to_py_function string C function for converting to Python object
# from_py_function string C function for constructing from Python object
#
-
+
to_py_function = None
from_py_function = None
exception_value = None
def create_to_py_utility_code(self, env):
return self.to_py_function is not None
-
+
def create_from_py_utility_code(self, env):
return self.from_py_function is not None
class CVoidType(CType):
+ #
+ # C "void" type
+ #
+
is_void = 1
-
+
def __repr__(self):
return "<CVoidType>"
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
- base = public_decl("void", dll_linkage)
- return self.base_declaration_code(base, entity_code)
-
+ if pyrex or for_display:
+ base_code = "void"
+ else:
+ base_code = public_decl("void", dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
+
def is_complete(self):
return 0
# rank integer Relative size
# signed integer 0 = unsigned, 1 = unspecified, 2 = explicitly signed
#
-
+
is_numeric = 1
default_value = "0"
-
+ has_attributes = True
+ scope = None
+
sign_words = ("unsigned ", "", "signed ")
-
+
def __init__(self, rank, signed = 1):
self.rank = rank
self.signed = signed
-
+
def sign_and_name(self):
s = self.sign_words[self.signed]
n = rank_to_type_name[self.rank]
return s + n
-
+
def __repr__(self):
return "<CNumericType %s>" % self.sign_and_name()
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
- base = public_decl(self.sign_and_name(), dll_linkage)
- if for_display:
- base = base.replace('PY_LONG_LONG', 'long long')
- return self.base_declaration_code(base, entity_code)
+ type_name = self.sign_and_name()
+ if pyrex or for_display:
+ base_code = type_name.replace('PY_LONG_LONG', 'long long')
+ else:
+ base_code = public_decl(type_name, dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
+
+ def attributes_known(self):
+ if self.scope is None:
+ import Symtab
+ self.scope = scope = Symtab.CClassScope(
+ '',
+ None,
+ visibility="extern")
+ scope.parent_type = self
+ scope.directives = {}
+ entry = scope.declare_cfunction(
+ "conjugate",
+ CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True),
+ pos=None,
+ defining=1,
+ cname=" ")
+ return True
type_conversion_predeclarations = ""
""",
impl="""
static CYTHON_INLINE %(type)s __Pyx_PyInt_from_py_%(TypeName)s(PyObject* x) {
- const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
- const int is_unsigned = neg_one > const_zero;
+ const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0;
+ const int is_unsigned = const_zero < neg_one;
if (sizeof(%(type)s) == sizeof(char)) {
if (is_unsigned)
return (%(type)s)__Pyx_PyInt_AsUnsignedChar(x);
return (%(type)s)__Pyx_PyInt_AsUnsignedLongLong(x);
else
return (%(type)s)__Pyx_PyInt_AsSignedLongLong(x);
-#if 0
- } else if (sizeof(%(type)s) > sizeof(short) &&
- sizeof(%(type)s) < sizeof(int)) { /* __int32 ILP64 ? */
- if (is_unsigned)
- return (%(type)s)__Pyx_PyInt_AsUnsignedInt(x);
- else
- return (%(type)s)__Pyx_PyInt_AsSignedInt(x);
-#endif
+ } else {
+ %(type)s val;
+ PyObject *v = __Pyx_PyNumber_Int(x);
+ #if PY_VERSION_HEX < 0x03000000
+ if (likely(v) && !PyLong_Check(v)) {
+ PyObject *tmp = v;
+ v = PyNumber_Long(tmp);
+ Py_DECREF(tmp);
+ }
+ #endif
+ if (likely(v)) {
+ int one = 1; int is_little = (int)*(unsigned char *)&one;
+ unsigned char *bytes = (unsigned char *)&val;
+ int ret = _PyLong_AsByteArray((PyLongObject *)v,
+ bytes, sizeof(val),
+ is_little, !is_unsigned);
+ Py_DECREF(v);
+ if (likely(!ret))
+ return val;
+ }
+ return (%(type)s)-1;
}
- PyErr_SetString(PyExc_TypeError, "%(TypeName)s");
- return (%(type)s)-1;
}
""")
""",
impl="""
static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
- const %(type)s neg_one = (%(type)s)-1, const_zero = 0;
- const int is_unsigned = neg_one > const_zero;
- if (sizeof(%(type)s) < sizeof(long)) {
+ const %(type)s neg_one = (%(type)s)-1, const_zero = (%(type)s)0;
+ const int is_unsigned = const_zero < neg_one;
+ if ((sizeof(%(type)s) == sizeof(char)) ||
+ (sizeof(%(type)s) == sizeof(short))) {
return PyInt_FromLong((long)val);
- } else if (sizeof(%(type)s) == sizeof(long)) {
+ } else if ((sizeof(%(type)s) == sizeof(int)) ||
+ (sizeof(%(type)s) == sizeof(long))) {
if (is_unsigned)
return PyLong_FromUnsignedLong((unsigned long)val);
else
return PyInt_FromLong((long)val);
- } else { /* (sizeof(%(type)s) > sizeof(long)) */
+ } else if (sizeof(%(type)s) == sizeof(PY_LONG_LONG)) {
if (is_unsigned)
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)val);
else
return PyLong_FromLongLong((PY_LONG_LONG)val);
+ } else {
+ int one = 1; int little = (int)*(unsigned char *)&one;
+ unsigned char *bytes = (unsigned char *)&val;
+ return _PyLong_FromByteArray(bytes, sizeof(%(type)s),
+ little, !is_unsigned);
}
}
""")
is_int = 1
typedef_flag = 0
- to_py_function = "PyInt_FromLong"
- from_py_function = "__Pyx_PyInt_AsInt"
+ to_py_function = None
+ from_py_function = None
exception_value = -1
- def __init__(self, rank, signed, is_returncode = 0):
+ def __init__(self, rank, signed = 1):
CNumericType.__init__(self, rank, signed)
- self.is_returncode = is_returncode
- if self.from_py_function == "__Pyx_PyInt_AsInt":
- self.from_py_function = self.get_type_conversion()
-
- def get_type_conversion(self):
- ctype = self.declaration_code('')
- bits = ctype.split(" ", 1)
- if len(bits) == 1:
- sign_word, type_name = "", bits[0]
+ if self.to_py_function is None:
+ self.to_py_function = self.get_to_py_type_conversion()
+ if self.from_py_function is None:
+ self.from_py_function = self.get_from_py_type_conversion()
+
+ def get_to_py_type_conversion(self):
+ if self.rank < list(rank_to_type_name).index('int'):
+ # This assumes sizeof(short) < sizeof(int)
+ return "PyInt_FromLong"
else:
- sign_word, type_name = bits
- type_name = type_name.replace("PY_LONG_LONG","long long")
- SignWord = sign_word.title()
- TypeName = type_name.title().replace(" ", "")
- if "Long" in TypeName:
+ # Py{Int|Long}_From[Unsigned]Long[Long]
+ Prefix = "Int"
+ SignWord = ""
+ TypeName = "Long"
+ if not self.signed:
+ Prefix = "Long"
+ SignWord = "Unsigned"
+ if self.rank >= list(rank_to_type_name).index('PY_LONG_LONG'):
+ Prefix = "Long"
+ TypeName = "LongLong"
+ return "Py%s_From%s%s" % (Prefix, SignWord, TypeName)
+
+ def get_from_py_type_conversion(self):
+ type_name = rank_to_type_name[self.rank]
+ type_name = type_name.replace("PY_LONG_LONG", "long long")
+ TypeName = type_name.title().replace(" ", "")
+ SignWord = self.sign_words[self.signed].strip().title()
+ if self.rank >= list(rank_to_type_name).index('long'):
utility_code = c_long_from_py_function
else:
utility_code = c_int_from_py_function
return src_type.is_int or src_type.is_enum or src_type is error_type
+class CAnonEnumType(CIntType):
+
+ is_enum = 1
+
+ def sign_and_name(self):
+ return 'int'
+
+
+class CReturnCodeType(CIntType):
+
+ to_py_function = "__Pyx_Owned_Py_None"
+
+ is_returncode = 1
+
+
class CBIntType(CIntType):
to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
- exception_check = 0
+ exception_check = 1 # for C++ bool
def __repr__(self):
return "<CNumericType bint>"
+ def __str__(self):
+ return 'bint'
-class CAnonEnumType(CIntType):
- is_enum = 1
+class CPyUCS4IntType(CIntType):
+ # Py_UCS4
- def sign_and_name(self):
- return 'int'
+ is_unicode_char = True
+ # Py_UCS4 coerces from and to single character unicode strings (or
+ # at most two characters on 16bit Unicode builds), but we also
+ # allow Python integers as input. The value range for Py_UCS4
+ # is 0..1114111, which is checked when converting from an integer
+ # value.
-class CUIntType(CIntType):
-
- to_py_function = "PyLong_FromUnsignedLong"
- exception_value = -1
+ to_py_function = "PyUnicode_FromOrdinal"
+ from_py_function = "__Pyx_PyObject_AsPy_UCS4"
+ def create_from_py_utility_code(self, env):
+ env.use_utility_code(pyobject_as_py_ucs4_utility_code)
+ return True
-class CLongType(CIntType):
+ def sign_and_name(self):
+ return "Py_UCS4"
+
+
+pyobject_as_py_ucs4_utility_code = UtilityCode(
+proto='''
+static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject*);
+''',
+impl='''
+static CYTHON_INLINE Py_UCS4 __Pyx_PyObject_AsPy_UCS4(PyObject* x) {
+ long ival;
+ if (PyUnicode_Check(x)) {
+ if (likely(PyUnicode_GET_SIZE(x) == 1)) {
+ return PyUnicode_AS_UNICODE(x)[0];
+ }
+ #if Py_UNICODE_SIZE == 2
+ else if (PyUnicode_GET_SIZE(x) == 2) {
+ Py_UCS4 high_val = PyUnicode_AS_UNICODE(x)[0];
+ if (high_val >= 0xD800 && high_val <= 0xDBFF) {
+ Py_UCS4 low_val = PyUnicode_AS_UNICODE(x)[1];
+ if (low_val >= 0xDC00 && low_val <= 0xDFFF) {
+ return 0x10000 + (((high_val & ((1<<10)-1)) << 10) | (low_val & ((1<<10)-1)));
+ }
+ }
+ }
+ #endif
+ PyErr_Format(PyExc_ValueError,
+ "only single character unicode strings can be converted to Py_UCS4, got length "
+ #if PY_VERSION_HEX < 0x02050000
+ "%d",
+ #else
+ "%zd",
+ #endif
+ PyUnicode_GET_SIZE(x));
+ return (Py_UCS4)-1;
+ }
+ ival = __Pyx_PyInt_AsLong(x);
+ if (unlikely(ival < 0)) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_OverflowError,
+ "cannot convert negative value to Py_UCS4");
+ return (Py_UCS4)-1;
+ } else if (unlikely(ival > 1114111)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "value too large to convert to Py_UCS4");
+ return (Py_UCS4)-1;
+ }
+ return (Py_UCS4)ival;
+}
+''')
- to_py_function = "PyInt_FromLong"
+class CPyUnicodeIntType(CIntType):
+ # Py_UNICODE
-class CULongType(CUIntType):
+ is_unicode_char = True
- to_py_function = "PyLong_FromUnsignedLong"
+ # Py_UNICODE coerces from and to single character unicode strings,
+ # but we also allow Python integers as input. The value range for
+ # Py_UNICODE is 0..1114111, which is checked when converting from
+ # an integer value.
+ to_py_function = "PyUnicode_FromOrdinal"
+ from_py_function = "__Pyx_PyObject_AsPy_UNICODE"
-class CLongLongType(CIntType):
+ def create_from_py_utility_code(self, env):
+ env.use_utility_code(pyobject_as_py_unicode_utility_code)
+ return True
- to_py_function = "PyLong_FromLongLong"
+ def sign_and_name(self):
+ return "Py_UNICODE"
+
+pyobject_as_py_unicode_utility_code = UtilityCode(
+proto='''
+static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject*);
+''',
+impl='''
+static CYTHON_INLINE Py_UNICODE __Pyx_PyObject_AsPy_UNICODE(PyObject* x) {
+ static long maxval = 0;
+ long ival;
+ if (PyUnicode_Check(x)) {
+ if (unlikely(PyUnicode_GET_SIZE(x) != 1)) {
+ PyErr_Format(PyExc_ValueError,
+ "only single character unicode strings can be converted to Py_UNICODE, got length "
+ #if PY_VERSION_HEX < 0x02050000
+ "%d",
+ #else
+ "%zd",
+ #endif
+ PyUnicode_GET_SIZE(x));
+ return (Py_UNICODE)-1;
+ }
+ return PyUnicode_AS_UNICODE(x)[0];
+ }
+ if (unlikely(!maxval))
+ maxval = (long)PyUnicode_GetMax();
+ ival = __Pyx_PyInt_AsLong(x);
+ if (unlikely(ival < 0)) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_OverflowError,
+ "cannot convert negative value to Py_UNICODE");
+ return (Py_UNICODE)-1;
+ } else if (unlikely(ival > maxval)) {
+ PyErr_SetString(PyExc_OverflowError,
+ "value too large to convert to Py_UNICODE");
+ return (Py_UNICODE)-1;
+ }
+ return (Py_UNICODE)ival;
+}
+''')
-class CULongLongType(CUIntType):
+class CPyHashTType(CIntType):
- to_py_function = "PyLong_FromUnsignedLongLong"
+ to_py_function = "__Pyx_PyInt_FromHash_t"
+ from_py_function = "__Pyx_PyInt_AsHash_t"
+ def sign_and_name(self):
+ return "Py_hash_t"
class CPySSizeTType(CIntType):
from_py_function = "__Pyx_PyIndex_AsSsize_t"
def sign_and_name(self):
- return rank_to_type_name[self.rank]
+ return "Py_ssize_t"
+class CSSizeTType(CIntType):
-class CSizeTType(CUIntType):
+ to_py_function = "PyInt_FromSsize_t"
+ from_py_function = "PyInt_AsSsize_t"
+
+ def sign_and_name(self):
+ return "Py_ssize_t"
+
+class CSizeTType(CIntType):
to_py_function = "__Pyx_PyInt_FromSize_t"
from_py_function = "__Pyx_PyInt_AsSize_t"
def sign_and_name(self):
- return rank_to_type_name[self.rank]
+ return "size_t"
class CFloatType(CNumericType):
from_py_function = "__pyx_PyFloat_AsDouble"
exception_value = -1
-
+
def __init__(self, rank, math_h_modifier = ''):
CNumericType.__init__(self, rank, 1)
self.math_h_modifier = math_h_modifier
-
+
def assignable_from_resolved_type(self, src_type):
return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type
class CComplexType(CNumericType):
-
+
is_complex = 1
to_py_function = "__pyx_PyComplex_FromComplex"
has_attributes = 1
scope = None
-
+
def __init__(self, real_type):
while real_type.is_typedef and not real_type.typedef_is_external:
real_type = real_type.typedef_base_type
self.funcsuffix = real_type.math_h_modifier
else:
self.funcsuffix = "_%s" % real_type.specialization_name()
-
+
self.real_type = real_type
CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed)
self.binops = {}
return self.real_type == other.real_type
else:
return False
-
+
def __ne__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
return self.real_type != other.real_type
def __hash__(self):
return ~hash(self.real_type)
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
- if for_display:
- base = public_decl(self.real_type.sign_and_name() + " complex", dll_linkage)
+ if pyrex or for_display:
+ real_code = self.real_type.declaration_code("", for_display, dll_linkage, pyrex)
+ base_code = "%s complex" % real_code
else:
- base = public_decl(self.sign_and_name(), dll_linkage)
- return self.base_declaration_code(base, entity_code)
+ base_code = public_decl(self.sign_and_name(), dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
def sign_and_name(self):
real_type_name = self.real_type.specialization_name()
real_type_name = real_type_name.replace('long__double','long_double')
+ real_type_name = real_type_name.replace('PY_LONG_LONG','long_long')
return Naming.type_prefix + real_type_name + "_complex"
-
+
def assignable_from(self, src_type):
# Temporary hack/feature disabling, see #441
if (not src_type.is_complex and src_type.is_numeric and src_type.is_typedef
return False
else:
return super(CComplexType, self).assignable_from(src_type)
-
+
def assignable_from_resolved_type(self, src_type):
return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type)
- or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type)
+ or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type)
or src_type is error_type)
-
+
def attributes_known(self):
if self.scope is None:
import Symtab
None,
visibility="extern")
scope.parent_type = self
- scope.declare_var("real", self.real_type, None, "real", is_cdef=True)
- scope.declare_var("imag", self.real_type, None, "imag", is_cdef=True)
+ scope.directives = {}
+ scope.declare_var("real", self.real_type, None, cname="real", is_cdef=True)
+ scope.declare_var("imag", self.real_type, None, cname="imag", is_cdef=True)
entry = scope.declare_cfunction(
"conjugate",
- CFuncType(self, [CFuncTypeArg("self", self, None)]),
+ CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True),
pos=None,
defining=1,
cname="__Pyx_c_conj%s" % self.funcsuffix)
complex_arithmetic_utility_code):
env.use_utility_code(
utility_code.specialize(
- self,
+ self,
real_type = self.real_type.declaration_code(''),
- m = self.funcsuffix))
+ m = self.funcsuffix,
+ is_float = self.real_type.is_float))
return True
def create_to_py_utility_code(self, env):
complex_from_py_utility_code):
env.use_utility_code(
utility_code.specialize(
- self,
+ self,
real_type = self.real_type.declaration_code(''),
- m = self.funcsuffix))
+ m = self.funcsuffix,
+ is_float = self.real_type.is_float))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name()
return True
-
+
def lookup_op(self, nargs, op):
try:
return self.binops[nargs, op]
def unary_op(self, op):
return self.lookup_op(1, op)
-
+
def binary_op(self, op):
return self.lookup_op(2, op)
-
+
complex_ops = {
(1, '-'): 'neg',
(1, 'zero'): 'is_zero',
#ifdef __cplusplus
#define __Pyx_c_is_zero%(m)s(z) ((z)==(%(real_type)s)0)
#define __Pyx_c_conj%(m)s(z) (::std::conj(z))
- /*#define __Pyx_c_abs%(m)s(z) (::std::abs(z))*/
+ #if %(is_float)s
+ #define __Pyx_c_abs%(m)s(z) (::std::abs(z))
+ #define __Pyx_c_pow%(m)s(a, b) (::std::pow(a, b))
+ #endif
#else
#define __Pyx_c_is_zero%(m)s(z) ((z)==0)
#define __Pyx_c_conj%(m)s(z) (conj%(m)s(z))
- /*#define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))*/
+ #if %(is_float)s
+ #define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))
+ #define __Pyx_c_pow%(m)s(a, b) (cpow%(m)s(a, b))
+ #endif
#endif
#else
static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s);
static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s);
- /*static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);*/
+ #if %(is_float)s
+ static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);
+ static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s, %(type)s);
+ #endif
#endif
""",
impl="""
z.imag = -a.imag;
return z;
}
-/*
- static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
-#if HAVE_HYPOT
- return hypot%(m)s(z.real, z.imag);
-#else
- return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
-#endif
- }
-*/
+ #if %(is_float)s
+ static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
+ #if !defined(HAVE_HYPOT) || defined(_MSC_VER)
+ return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
+ #else
+ return hypot%(m)s(z.real, z.imag);
+ #endif
+ }
+ static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s a, %(type)s b) {
+ %(type)s z;
+ %(real_type)s r, lnr, theta, z_r, z_theta;
+ if (b.imag == 0 && b.real == (int)b.real) {
+ if (b.real < 0) {
+ %(real_type)s denom = a.real * a.real + a.imag * a.imag;
+ a.real = a.real / denom;
+ a.imag = -a.imag / denom;
+ b.real = -b.real;
+ }
+ switch ((int)b.real) {
+ case 0:
+ z.real = 1;
+ z.imag = 0;
+ return z;
+ case 1:
+ return a;
+ case 2:
+ z = __Pyx_c_prod%(m)s(a, a);
+ return __Pyx_c_prod%(m)s(a, a);
+ case 3:
+ z = __Pyx_c_prod%(m)s(a, a);
+ return __Pyx_c_prod%(m)s(z, a);
+ case 4:
+ z = __Pyx_c_prod%(m)s(a, a);
+ return __Pyx_c_prod%(m)s(z, z);
+ }
+ }
+ if (a.imag == 0) {
+ if (a.real == 0) {
+ return a;
+ }
+ r = a.real;
+ theta = 0;
+ } else {
+ r = __Pyx_c_abs%(m)s(a);
+ theta = atan2%(m)s(a.imag, a.real);
+ }
+ lnr = log%(m)s(r);
+ z_r = exp%(m)s(lnr * b.real - theta * b.imag);
+ z_theta = theta * b.real + lnr * b.imag;
+ z.real = z_r * cos%(m)s(z_theta);
+ z.imag = z_r * sin%(m)s(z_theta);
+ return z;
+ }
+ #endif
#endif
""")
class CArrayType(CType):
# base_type CType Element type
# size integer or None Number of elements
-
+
is_array = 1
-
+
def __init__(self, base_type, size):
self.base_type = base_type
self.size = size
- if base_type is c_char_type:
+ if base_type in (c_char_type, c_uchar_type, c_schar_type):
self.is_string = 1
-
+
def __repr__(self):
return "<CArrayType %s %s>" % (self.size, repr(self.base_type))
-
+
def same_as_resolved_type(self, other_type):
return ((other_type.is_array and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
-
+
def assignable_from_resolved_type(self, src_type):
# Can't assign to a variable of an array type
return 0
-
+
def element_ptr_type(self):
return c_ptr_type(self.base_type)
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.size is not None:
dimension_code = self.size
return self.base_type.declaration_code(
"%s[%s]" % (entity_code, dimension_code),
for_display, dll_linkage, pyrex)
-
+
def as_argument_type(self):
return c_ptr_type(self.base_type)
-
+
def is_complete(self):
return self.size is not None
class CPtrType(CType):
# base_type CType Referenced type
-
+
is_ptr = 1
default_value = "0"
-
+
def __init__(self, base_type):
self.base_type = base_type
-
+
def __repr__(self):
return "<CPtrType %s>" % repr(self.base_type)
-
+
def same_as_resolved_type(self, other_type):
return ((other_type.is_ptr and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CPtrType.declaration_code: pointer to", self.base_type ###
return self.base_type.declaration_code(
"*%s" % entity_code,
for_display, dll_linkage, pyrex)
-
+
def assignable_from_resolved_type(self, other_type):
if other_type is error_type:
return 1
return self.base_type.pointer_assignable_from_resolved_type(other_type)
else:
return 0
- if (self.base_type.is_cpp_class and other_type.is_ptr
+ if (self.base_type.is_cpp_class and other_type.is_ptr
and other_type.base_type.is_cpp_class and other_type.base_type.is_subclass(self.base_type)):
return 1
if other_type.is_array or other_type.is_ptr:
return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
return 0
-
+
def specialize(self, values):
base_type = self.base_type.specialize(values)
if base_type == self.base_type:
class CNullPtrType(CPtrType):
is_null_ptr = 1
-
+
class CReferenceType(BaseType):
def __repr__(self):
return "<CReferenceType %s>" % repr(self.ref_base_type)
-
+
def __str__(self):
return "%s &" % self.ref_base_type
def as_argument_type(self):
return self
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
return self.ref_base_type.declaration_code(
"&%s" % entity_code,
for_display, dll_linkage, pyrex)
-
+
def specialize(self, values):
base_type = self.ref_base_type.specialize(values)
if base_type == self.ref_base_type:
# nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body
# templates [string] or None
-
+
is_cfunction = 1
original_sig = None
-
+
def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "",
nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0,
self.with_gil = with_gil
self.is_overridable = is_overridable
self.templates = templates
-
+
def __repr__(self):
arg_reprs = map(repr, self.args)
if self.has_varargs:
self.calling_convention_prefix(),
",".join(arg_reprs),
except_clause)
-
+
def calling_convention_prefix(self):
cc = self.calling_convention
if cc:
return cc + " "
else:
return ""
-
+
def same_c_signature_as(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(
other_type.resolve(), as_cmethod)
def compatible_signature_with(self, other_type, as_cmethod = 0):
return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod)
-
+
def compatible_signature_with_resolved_type(self, other_type, as_cmethod):
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ###
if as_cmethod:
self.args[0] = other_type.args[0]
return 1
-
-
+
+
def narrower_c_signature_than(self, other_type, as_cmethod = 0):
return self.narrower_c_signature_than_resolved_type(other_type.resolve(), as_cmethod)
-
+
def narrower_c_signature_than_resolved_type(self, other_type, as_cmethod):
if other_type is error_type:
return 1
sc1 = self.calling_convention == '__stdcall'
sc2 = other.calling_convention == '__stdcall'
return sc1 == sc2
-
+
def same_exception_signature_as(self, other_type):
return self.same_exception_signature_as_resolved_type(
other_type.resolve())
def same_exception_signature_as_resolved_type(self, other_type):
return self.exception_value == other_type.exception_value \
and self.exception_check == other_type.exception_check
-
+
def same_as_resolved_type(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \
and self.same_exception_signature_as_resolved_type(other_type) \
and self.nogil == other_type.nogil
-
+
def pointer_assignable_from_resolved_type(self, other_type):
return self.same_c_signature_as_resolved_type(other_type) \
and self.same_exception_signature_as_resolved_type(other_type) \
and not (self.nogil and not other_type.nogil)
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0,
with_calling_convention = 1):
arg_decl_list = []
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
-
+
def function_header_code(self, func_name, arg_code):
return "%s%s(%s)" % (self.calling_convention_prefix(),
func_name, arg_code)
def signature_cast_string(self):
s = self.declaration_code("(*)", with_calling_convention=False)
return '(%s)' % s
-
+
def specialize(self, values):
if self.templates is None:
new_templates = None
is_overridable = self.is_overridable,
optional_arg_count = self.optional_arg_count,
templates = new_templates)
-
+
def opt_arg_cname(self, arg_name):
return self.op_arg_struct.base_type.scope.lookup(arg_name).cname
# cname string
# type PyrexType
# pos source file position
-
+
+ # FIXME: is this the right setup? should None be allowed here?
+ not_none = False
+ or_none = False
+ accept_none = True
+
def __init__(self, name, type, pos, cname=None):
self.name = name
if cname is not None:
self.cname = Naming.var_prefix + name
self.type = type
self.pos = pos
- self.not_none = False
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
-
+
def __repr__(self):
return "%s:%s" % (self.name, repr(self.type))
-
+
def declaration_code(self, for_display = 0):
return self.type.declaration_code(self.cname, for_display)
-
+
def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
return isinstance(other, StructUtilityCode) and self.header == other.header
def __hash__(self):
return hash(self.header)
-
+
def put_code(self, output):
code = output['utility_code_def']
proto = output['utility_code_proto']
-
+
code.putln("%s {" % self.header)
code.putln("PyObject* res;")
code.putln("PyObject* member;")
if self.forward_decl:
proto.putln(self.type.declaration_code('') + ';')
proto.putln(self.header + ";")
-
+
class CStructOrUnionType(CType):
# name string
# scope StructOrUnionScope, or None if incomplete
# typedef_flag boolean
# packed boolean
-
+
# entry Entry
-
+
is_struct_or_union = 1
has_attributes = 1
-
+
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name
self.cname = cname
self.exception_check = True
self._convert_code = None
self.packed = packed
-
+
def create_to_py_utility_code(self, env):
if env.outer_scope is None:
return False
return False
forward_decl = (self.entry.visibility != 'extern')
self._convert_code = StructUtilityCode(self, forward_decl)
-
+
env.use_utility_code(self._convert_code)
return True
-
+
def __repr__(self):
return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
- if pyrex:
- return self.base_declaration_code(self.name, entity_code)
+ if pyrex or for_display:
+ base_code = self.name
else:
- if for_display:
- base = self.name
- elif self.typedef_flag:
- base = self.cname
+ if self.typedef_flag:
+ base_code = self.cname
else:
- base = "%s %s" % (self.kind, self.cname)
- return self.base_declaration_code(public_decl(base, dll_linkage), entity_code)
+ base_code = "%s %s" % (self.kind, self.cname)
+ base_code = public_decl(base_code, dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
def __eq__(self, other):
try:
def is_complete(self):
return self.scope is not None
-
+
def attributes_known(self):
return self.is_complete()
# cname string
# scope CppClassScope
# templates [string] or None
-
+
is_cpp_class = 1
has_attributes = 1
exception_check = True
namespace = None
-
+
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name
self.cname = cname
error(pos, "'%s' type is not a template" % self);
return PyrexTypes.error_type
if len(self.templates) != len(template_values):
- error(pos, "%s templated type receives %d arguments, got %d" %
+ error(pos, "%s templated type receives %d arguments, got %d" %
(self.name, len(self.templates), len(template_values)))
return error_type
return self.specialize(dict(zip(self.templates, template_values)))
-
+
def specialize(self, values):
if not self.templates and not self.namespace:
return self
specialized.namespace = self.namespace.specialize(values)
return specialized
- def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
+ def declaration_code(self, entity_code,
+ for_display = 0, dll_linkage = None, pyrex = 0):
if self.templates:
- template_strings = [param.declaration_code('', for_display, pyrex) for param in self.templates]
- templates = "<" + ",".join(template_strings) + ">"
+ template_strings = [param.declaration_code('', for_display, None, pyrex)
+ for param in self.templates]
+ templates = "<%s>" % ",".join(template_strings)
+ if templates[-2:] == ">>":
+ templates = templates[:-2] + "> >"
else:
templates = ""
- if for_display or pyrex:
- name = self.name
+ if pyrex or for_display:
+ base_code = "%s%s" % (self.name, templates)
else:
+ base_code = "%s%s" % (self.cname, templates)
if self.namespace is not None:
- name = "%s::%s" % (self.namespace.declaration_code(''), self.cname)
- else:
- name = self.cname
- return "%s%s %s" % (name, templates, entity_code)
+ base_code = "%s::%s" % (self.namespace.declaration_code(''), base_code)
+ base_code = public_decl(base_code, dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
def is_subclass(self, other_type):
# TODO(danilo): Handle templates.
if base_class.is_subclass(other_type):
return 1
return 0
-
+
def same_as_resolved_type(self, other_type):
if other_type.is_cpp_class:
if self == other_type:
if other_type is error_type:
return True
return other_type.is_cpp_class and other_type.is_subclass(self)
-
+
def attributes_known(self):
return self.scope is not None
class TemplatePlaceholderType(CType):
-
+
def __init__(self, name):
self.name = name
-
- def declaration_code(self, entity_code, for_display = 0, dll_linkage = None, pyrex = 0):
+
+ def declaration_code(self, entity_code,
+ for_display = 0, dll_linkage = None, pyrex = 0):
if entity_code:
return self.name + " " + entity_code
else:
return self.name
-
+
def specialize(self, values):
if self in values:
return values[self]
return self.name == other_type.name
else:
return 0
-
+
def __hash__(self):
return hash(self.name)
-
+
def __cmp__(self, other):
if isinstance(other, TemplatePlaceholderType):
return cmp(self.name, other.name)
self.cname = cname
self.values = []
self.typedef_flag = typedef_flag
-
+
def __str__(self):
return self.name
-
+
def __repr__(self):
return "<CEnumType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
- if pyrex:
- return self.base_declaration_code(self.cname, entity_code)
+ if pyrex or for_display:
+ base_code = self.name
else:
if self.typedef_flag:
- base = self.cname
+ base_code = self.cname
else:
- base = "enum %s" % self.cname
- return self.base_declaration_code(public_decl(base, dll_linkage), entity_code)
+ base_code = "enum %s" % self.cname
+ base_code = public_decl(base_code, dll_linkage)
+ return self.base_declaration_code(base_code, entity_code)
class CStringType(object):
is_string = 1
is_unicode = 0
-
- to_py_function = "__Pyx_PyBytes_FromString"
- from_py_function = "__Pyx_PyBytes_AsString"
+
+ to_py_function = "PyBytes_FromString"
+ from_py_function = "PyBytes_AsString"
exception_value = "NULL"
def literal_code(self, value):
class CUTF8CharArrayType(CStringType, CArrayType):
# C 'char []' type.
-
+
is_unicode = 1
-
+
to_py_function = "PyUnicode_DecodeUTF8"
exception_value = "NULL"
-
+
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharArrayType(CStringType, CArrayType):
# C 'char []' type.
-
+
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
-
+
class CCharPtrType(CStringType, CPtrType):
# C 'char *' type.
-
+
def __init__(self):
CPtrType.__init__(self, c_char_type)
class CUCharPtrType(CStringType, CPtrType):
# C 'unsigned char *' type.
-
+
to_py_function = "__Pyx_PyBytes_FromUString"
from_py_function = "__Pyx_PyBytes_AsUString"
class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined.
-
+
is_unspecified = 1
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<unspecified>"
-
+
def same_as_resolved_type(self, other_type):
return False
-
+
class ErrorType(PyrexType):
# Used to prevent propagation of error messages.
-
+
is_error = 1
exception_value = "0"
exception_check = 0
to_py_function = "dummy"
from_py_function = "dummy"
-
+
def create_to_py_utility_code(self, env):
return True
-
+
def create_from_py_utility_code(self, env):
return True
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<error>"
-
+
def same_as_resolved_type(self, other_type):
return 1
-
+
def error_condition(self, result_code):
return "dummy"
"short", # 1
"int", # 2
"long", # 3
- "Py_ssize_t", # 4
- "size_t", # 5
- "PY_LONG_LONG", # 6
- "float", # 7
- "double", # 8
- "long double", # 9
+ "PY_LONG_LONG", # 4
+ "float", # 5
+ "double", # 6
+ "long double", # 7
)
-py_object_type = PyObjectType()
-
-c_void_type = CVoidType()
-c_void_ptr_type = CPtrType(c_void_type)
-c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
-
-c_uchar_type = CIntType(0, 0)
-c_ushort_type = CIntType(1, 0)
-c_uint_type = CUIntType(2, 0)
-c_ulong_type = CULongType(3, 0)
-c_ulonglong_type = CULongLongType(6, 0)
-
-c_char_type = CIntType(0, 1)
-c_short_type = CIntType(1, 1)
-c_int_type = CIntType(2, 1)
-c_long_type = CLongType(3, 1)
-c_longlong_type = CLongLongType(6, 1)
-c_bint_type = CBIntType(2, 1)
-
-c_schar_type = CIntType(0, 2)
-c_sshort_type = CIntType(1, 2)
-c_sint_type = CIntType(2, 2)
-c_slong_type = CLongType(3, 2)
-c_slonglong_type = CLongLongType(6, 2)
+RANK_INT = list(rank_to_type_name).index('int')
+RANK_LONG = list(rank_to_type_name).index('long')
+UNSIGNED = 0
+SIGNED = 2
-c_py_ssize_t_type = CPySSizeTType(4, 2)
-c_size_t_type = CSizeTType(5, 0)
-c_float_type = CFloatType(7, math_h_modifier='f')
-c_double_type = CFloatType(8)
-c_longdouble_type = CFloatType(9, math_h_modifier='l')
+py_object_type = PyObjectType()
-c_double_complex_type = CComplexType(c_double_type)
+c_void_type = CVoidType()
+
+c_uchar_type = CIntType(0, UNSIGNED)
+c_ushort_type = CIntType(1, UNSIGNED)
+c_uint_type = CIntType(2, UNSIGNED)
+c_ulong_type = CIntType(3, UNSIGNED)
+c_ulonglong_type = CIntType(4, UNSIGNED)
+
+c_char_type = CIntType(0)
+c_short_type = CIntType(1)
+c_int_type = CIntType(2)
+c_long_type = CIntType(3)
+c_longlong_type = CIntType(4)
+
+c_schar_type = CIntType(0, SIGNED)
+c_sshort_type = CIntType(1, SIGNED)
+c_sint_type = CIntType(2, SIGNED)
+c_slong_type = CIntType(3, SIGNED)
+c_slonglong_type = CIntType(4, SIGNED)
+
+c_float_type = CFloatType(5, math_h_modifier='f')
+c_double_type = CFloatType(6)
+c_longdouble_type = CFloatType(7, math_h_modifier='l')
+
+c_float_complex_type = CComplexType(c_float_type)
+c_double_complex_type = CComplexType(c_double_type)
+c_longdouble_complex_type = CComplexType(c_longdouble_type)
+
+c_anon_enum_type = CAnonEnumType(-1)
+c_returncode_type = CReturnCodeType(RANK_INT)
+c_bint_type = CBIntType(RANK_INT)
+c_py_unicode_type = CPyUnicodeIntType(RANK_INT-0.5, UNSIGNED)
+c_py_ucs4_type = CPyUCS4IntType(RANK_LONG-0.5, UNSIGNED)
+c_py_hash_t_type = CPyHashTType(RANK_LONG+0.5, SIGNED)
+c_py_ssize_t_type = CPySSizeTType(RANK_LONG+0.5, SIGNED)
+c_ssize_t_type = CSSizeTType(RANK_LONG+0.5, SIGNED)
+c_size_t_type = CSizeTType(RANK_LONG+0.5, UNSIGNED)
c_null_ptr_type = CNullPtrType(c_void_type)
+c_void_ptr_type = CPtrType(c_void_type)
+c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
c_char_array_type = CCharArrayType(None)
c_char_ptr_type = CCharPtrType()
c_uchar_ptr_type = CUCharPtrType()
c_utf8_char_array_type = CUTF8CharArrayType(None)
c_char_ptr_ptr_type = CPtrType(c_char_ptr_type)
c_int_ptr_type = CPtrType(c_int_type)
+c_py_unicode_ptr_type = CPtrType(c_py_unicode_type)
c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type)
+c_ssize_t_ptr_type = CPtrType(c_ssize_t_type)
c_size_t_ptr_type = CPtrType(c_size_t_type)
-c_returncode_type = CIntType(2, 1, is_returncode = 1)
-
-c_anon_enum_type = CAnonEnumType(-1, 1)
# the Py_buffer type is defined in Builtin.py
c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer")
error_type = ErrorType()
unspecified_type = UnspecifiedType()
-sign_and_rank_to_type = {
- #(signed, rank)
- (0, 0): c_uchar_type,
- (0, 1): c_ushort_type,
- (0, 2): c_uint_type,
- (0, 3): c_ulong_type,
- (0, 6): c_ulonglong_type,
-
- (1, 0): c_char_type,
- (1, 1): c_short_type,
- (1, 2): c_int_type,
- (1, 3): c_long_type,
- (1, 6): c_longlong_type,
-
- (2, 0): c_schar_type,
- (2, 1): c_sshort_type,
- (2, 2): c_sint_type,
- (2, 3): c_slong_type,
- (2, 6): c_slonglong_type,
-
- (0, 4): c_py_ssize_t_type,
- (1, 4): c_py_ssize_t_type,
- (2, 4): c_py_ssize_t_type,
- (0, 5): c_size_t_type,
- (1, 5): c_size_t_type,
- (2, 5): c_size_t_type,
-
- (1, 7): c_float_type,
- (1, 8): c_double_type,
- (1, 9): c_longdouble_type,
-# In case we're mixing unsigned ints and floats...
- (0, 7): c_float_type,
- (0, 8): c_double_type,
- (0, 9): c_longdouble_type,
-}
-
modifiers_and_name_to_type = {
- #(signed, longness, name)
- (0, 0, "char"): c_uchar_type,
+ #(signed, longness, name) : type
+ (0, 0, "char"): c_uchar_type,
+ (1, 0, "char"): c_char_type,
+ (2, 0, "char"): c_schar_type,
+
(0, -1, "int"): c_ushort_type,
- (0, 0, "int"): c_uint_type,
- (0, 1, "int"): c_ulong_type,
- (0, 2, "int"): c_ulonglong_type,
- (1, 0, "void"): c_void_type,
- (1, 0, "char"): c_char_type,
+ (0, 0, "int"): c_uint_type,
+ (0, 1, "int"): c_ulong_type,
+ (0, 2, "int"): c_ulonglong_type,
+
(1, -1, "int"): c_short_type,
- (1, 0, "int"): c_int_type,
- (1, 1, "int"): c_long_type,
- (1, 2, "int"): c_longlong_type,
- (1, 0, "float"): c_float_type,
- (1, 0, "double"): c_double_type,
- (1, 1, "double"): c_longdouble_type,
- (1, 0, "object"): py_object_type,
- (1, 0, "bint"): c_bint_type,
- (2, 0, "char"): c_schar_type,
+ (1, 0, "int"): c_int_type,
+ (1, 1, "int"): c_long_type,
+ (1, 2, "int"): c_longlong_type,
+
(2, -1, "int"): c_sshort_type,
- (2, 0, "int"): c_sint_type,
- (2, 1, "int"): c_slong_type,
- (2, 2, "int"): c_slonglong_type,
+ (2, 0, "int"): c_sint_type,
+ (2, 1, "int"): c_slong_type,
+ (2, 2, "int"): c_slonglong_type,
- (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
- (0, 0, "size_t") : c_size_t_type,
+ (1, 0, "float"): c_float_type,
+ (1, 0, "double"): c_double_type,
+ (1, 1, "double"): c_longdouble_type,
- (1, 0, "long"): c_long_type,
- (1, 0, "short"): c_short_type,
- (1, 0, "longlong"): c_longlong_type,
- (1, 0, "bint"): c_bint_type,
-}
+ (1, 0, "complex"): c_double_complex_type, # C: float, Python: double => Python wins
+ (1, 0, "floatcomplex"): c_float_complex_type,
+ (1, 0, "doublecomplex"): c_double_complex_type,
+ (1, 1, "doublecomplex"): c_longdouble_complex_type,
-def is_promotion0(src_type, dst_type):
- if src_type.is_numeric and dst_type.is_numeric:
- if src_type.is_int and dst_type.is_int:
- if src_type.is_enum:
- return True
- elif src_type.signed:
- return dst_type.signed and src_type.rank <= dst_type.rank
- elif dst_type.signed: # and not src_type.signed
- src_type.rank < dst_type.rank
- else:
- return src_type.rank <= dst_type.rank
- elif src_type.is_float and dst_type.is_float:
- return src_type.rank <= dst_type.rank
- else:
- return False
- else:
- return False
+ #
+ (1, 0, "void"): c_void_type,
+
+ (1, 0, "bint"): c_bint_type,
+ (0, 0, "Py_UNICODE"): c_py_unicode_type,
+ (0, 0, "Py_UCS4"): c_py_ucs4_type,
+ (2, 0, "Py_hash_t"): c_py_hash_t_type,
+ (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
+ (2, 0, "ssize_t") : c_ssize_t_type,
+ (0, 0, "size_t") : c_size_t_type,
+
+ (1, 0, "object"): py_object_type,
+}
def is_promotion(src_type, dst_type):
# It's hard to find a hard definition of promotion, but empirical
- # evidence suggests that the below is all that's allowed.
+ # evidence suggests that the below is all that's allowed.
if src_type.is_numeric:
if dst_type.same_as(c_int_type):
- return src_type.is_enum or (src_type.is_int and (not src_type.signed) + src_type.rank < dst_type.rank)
+ unsigned = (not src_type.signed)
+ return (src_type.is_enum or
+ (src_type.is_int and
+ unsigned + src_type.rank < dst_type.rank))
elif dst_type.same_as(c_double_type):
return src_type.is_float and src_type.rank <= dst_type.rank
return False
functions based on how much work must be done to convert the
arguments, with the following priorities:
* identical types or pointers to identical types
- * promotions
+ * promotions
* non-Python types
That is, we prefer functions where no arguments need converted,
and failing that, functions where only promotions are required, and
the same weight, we return None (as there is no best match). If pos
is not None, we also generate an error.
"""
- # TODO: args should be a list of types, not a list of Nodes.
+ # TODO: args should be a list of types, not a list of Nodes.
actual_nargs = len(args)
candidates = []
errors.append((func, error_mesg))
continue
candidates.append((func, func_type))
-
+
# Optimize the most common case of no overloading...
if len(candidates) == 1:
return candidates[0][0]
elif len(candidates) == 0:
- if len(errors) == 1 and pos is not None:
- error(pos, errors[0][1])
+ if pos is not None:
+ if len(errors) == 1:
+ error(pos, errors[0][1])
+ else:
+ error(pos, "no suitable method found")
return None
-
+
possibilities = []
bad_types = []
for func, func_type in candidates:
error(pos, "no suitable method found")
return None
-
def widest_numeric_type(type1, type2):
# Given two numeric types, return the narrowest type
# encompassing both of them.
if type1 == type2:
- return type1
- if type1.is_complex:
- if type2.is_complex:
- return CComplexType(widest_numeric_type(type1.real_type, type2.real_type))
- else:
- return CComplexType(widest_numeric_type(type1.real_type, type2))
- elif type2.is_complex:
- return CComplexType(widest_numeric_type(type1, type2.real_type))
- if type1.is_enum and type2.is_enum:
- return c_int_type
- elif type1 is type2:
- return type1
- elif (type1.signed and type2.signed) or (not type1.signed and not type2.signed):
- if type2.rank > type1.rank:
- return type2
- else:
- return type1
+ widest_type = type1
+ elif type1.is_complex or type2.is_complex:
+ def real_type(ntype):
+ if ntype.is_complex:
+ return ntype.real_type
+ return ntype
+ widest_type = CComplexType(
+ widest_numeric_type(
+ real_type(type1),
+ real_type(type2)))
+ elif type1.is_enum and type2.is_enum:
+ widest_type = c_int_type
+ elif type1.rank < type2.rank:
+ widest_type = type2
+ elif type1.rank > type2.rank:
+ widest_type = type1
+ elif type1.signed < type2.signed:
+ widest_type = type1
else:
- return sign_and_rank_to_type[min(type1.signed, type2.signed), max(type1.rank, type2.rank)]
+ widest_type = type2
+ return widest_type
+
+def independent_spanning_type(type1, type2):
+ # Return a type assignable independently from both type1 and
+ # type2, but do not require any interoperability between the two.
+ # For example, in "True * 2", it is safe to assume an integer
+ # result type (so spanning_type() will do the right thing),
+ # whereas "x = True or 2" must evaluate to a type that can hold
+ # both a boolean value and an integer, so this function works
+ # better.
+ if type1 == type2:
+ return type1
+ elif (type1 is c_bint_type or type2 is c_bint_type) and (type1.is_numeric and type2.is_numeric):
+ # special case: if one of the results is a bint and the other
+ # is another C integer, we must prevent returning a numeric
+ # type so that we do not lose the ability to coerce to a
+ # Python bool if we have to.
+ return py_object_type
+ span_type = _spanning_type(type1, type2)
+ if span_type is None:
+ return error_type
+ return span_type
def spanning_type(type1, type2):
- # Return a type assignable from both type1 and type2.
- if type1 is py_object_type or type2 is py_object_type:
- return py_object_type
- elif type1 == type2:
+ # Return a type assignable from both type1 and type2, or
+ # py_object_type if no better type is found. Assumes that the
+ # code that calls this will try a coercion afterwards, which will
+ # fail if the types cannot actually coerce to a py_object_type.
+ if type1 == type2:
return type1
- elif type1.is_numeric and type2.is_numeric:
+ elif type1 is py_object_type or type2 is py_object_type:
+ return py_object_type
+ elif type1 is c_py_unicode_type or type2 is c_py_unicode_type:
+ # Py_UNICODE behaves more like a string than an int
+ return py_object_type
+ span_type = _spanning_type(type1, type2)
+ if span_type is None:
+ return py_object_type
+ return span_type
+
+def _spanning_type(type1, type2):
+ if type1.is_numeric and type2.is_numeric:
return widest_numeric_type(type1, type2)
elif type1.is_builtin_type and type1.name == 'float' and type2.is_numeric:
return widest_numeric_type(c_double_type, type2)
elif type2.is_builtin_type and type2.name == 'float' and type1.is_numeric:
return widest_numeric_type(type1, c_double_type)
- elif type1.is_pyobject ^ type2.is_pyobject:
- return py_object_type
elif type1.is_extension_type and type2.is_extension_type:
- if type1.typeobj_is_imported() or type2.typeobj_is_imported():
- return py_object_type
- while True:
- if type1.subtype_of(type2):
- return type2
- elif type2.subtype_of(type1):
- return type1
- type1, type2 = type1.base_type, type2.base_type
- if type1 is None or type2 is None:
- return py_object_type
+ return widest_extension_type(type1, type2)
+ elif type1.is_pyobject or type2.is_pyobject:
+ return py_object_type
elif type1.assignable_from(type2):
if type1.is_extension_type and type1.typeobj_is_imported():
# external types are unsafe, so we use PyObject instead
return py_object_type
return type2
else:
+ return None
+
+def widest_extension_type(type1, type2):
+ if type1.typeobj_is_imported() or type2.typeobj_is_imported():
return py_object_type
-
+ while True:
+ if type1.subtype_of(type2):
+ return type2
+ elif type2.subtype_of(type1):
+ return type1
+ type1, type2 = type1.base_type, type2.base_type
+ if type1 is None or type2 is None:
+ return py_object_type
+
def simple_c_type(signed, longness, name):
# Find type descriptor for simple type given name and modifiers.
# Returns None if arguments don't make sense.
return modifiers_and_name_to_type.get((signed, longness, name))
-
+
def parse_basic_type(name):
base = None
if name.startswith('p_'):
base = parse_basic_type(name[:-1])
if base:
return CPtrType(base)
- elif name.startswith('u'):
- return simple_c_type(0, 0, name[1:])
+ #
+ basic_type = simple_c_type(1, 0, name)
+ if basic_type:
+ return basic_type
+ #
+ signed = 1
+ longness = 0
+ if name == 'Py_UNICODE':
+ signed = 0
+ elif name == 'Py_UCS4':
+ signed = 0
+ elif name == 'Py_hash_t':
+ signed = 2
+ elif name == 'Py_ssize_t':
+ signed = 2
+ elif name == 'ssize_t':
+ signed = 2
+ elif name == 'size_t':
+ signed = 0
else:
- return simple_c_type(1, 0, name)
+ if name.startswith('u'):
+ name = name[1:]
+ signed = 0
+ elif (name.startswith('s') and
+ not name.startswith('short')):
+ name = name[1:]
+ signed = 2
+ longness = 0
+ while name.startswith('short'):
+ name = name.replace('short', '', 1).strip()
+ longness -= 1
+ while name.startswith('long'):
+ name = name.replace('long', '', 1).strip()
+ longness += 1
+ if longness != 0 and not name:
+ name = 'int'
+ return simple_c_type(signed, longness, name)
def c_array_type(base_type, size):
# Construct a C array type.
return error_type
else:
return CReferenceType(base_type)
-
-def Node_to_type(node, env):
- from ExprNodes import NameNode, AttributeNode, StringNode, error
- if isinstance(node, StringNode):
- node = NameNode(node.pos, name=node.value)
- if isinstance(node, NameNode) and node.name in rank_to_type_name:
- return simple_c_type(1, 0, node.name)
- elif isinstance(node, (AttributeNode, NameNode)):
- node.analyze_types(env)
- if not node.entry.is_type:
- pass
- else:
- error(node.pos, "Bad type")
def same_type(type1, type2):
return type1.same_as(type2)
-
+
def assignable_from(type1, type2):
return type1.assignable_from(type2)
type_conversion_predeclarations = """
/* Type Conversion Predeclarations */
-#if PY_MAJOR_VERSION < 3
-#define __Pyx_PyBytes_FromString PyString_FromString
-#define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize
-#define __Pyx_PyBytes_AsString PyString_AsString
-#else
-#define __Pyx_PyBytes_FromString PyBytes_FromString
-#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize
-#define __Pyx_PyBytes_AsString PyBytes_AsString
-#endif
-
-#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s)
-#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) __Pyx_PyBytes_AsString(s))
+#define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
+#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s))
+#define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None)
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
""" + type_conversion_functions
-