src = PyTypeTestNode(src, dst_type, env)
elif src.type.is_pyobject:
src = CoerceFromPyTypeNode(dst_type, src, env)
+ elif (dst_type.is_complex
+ and src_type != dst_type
+ and dst_type.assignable_from(src_type)
+ and not env.directives['c99_complex']):
+ src = CoerceToComplexNode(src, dst_type, env)
else: # neither src nor dst are py types
# Added the string comparison, since for c types that
# is enough, but Cython gets confused when the types are
- # in different files.
+ # in different pxi files.
if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
error(self.pos, "Cannot assign type '%s' to '%s'" %
(src.type, dst_type))
type = PyrexTypes.c_long_type
def coerce_to(self, dst_type, env):
- if dst_type.is_numeric:
+ if dst_type.is_numeric and not dst_type.is_complex:
self.type = PyrexTypes.c_long_type
return self
# Arrange for a Python version of the number to be pre-allocated
# Imaginary number literal
#
# value float imaginary part
+
+ type = PyrexTypes.c_double_complex_type
def calculate_constant_result(self):
self.constant_result = complex(0.0, self.value)
return complex(0.0, self.value)
def analyse_types(self, env):
- self.type = py_object_type
- self.gil_check(env)
- self.is_temp = 1
+ self.type.create_declaration_utility_code(env)
+
+ def coerce_to(self, dst_type, env):
+ # Arrange for a Python version of the number to be pre-allocated
+ # when coercing to a Python type.
+ if dst_type.is_pyobject:
+ self.is_temp = 1
+ self.gil_check(env)
+ self.type = PyrexTypes.py_object_type
+ # We still need to perform normal coerce_to processing on the
+ # result, because we might be coercing to an extension type,
+ # in which case a type test node will be needed.
+ return AtomicNewTempExprNode.coerce_to(self, dst_type, env)
gil_message = "Constructing complex number"
+ def calculate_result_code(self):
+ if self.type.is_pyobject:
+ return self.result()
+ elif self.c99_complex:
+ return "%rj" % float(self.value)
+ else:
+ return "%s(0, %r)" % (self.type.from_parts, float(self.value))
+
def generate_result_code(self, code):
- code.putln(
- "%s = PyComplex_FromDoubles(0.0, %r); %s" % (
- self.result(),
- float(self.value),
- code.error_goto_if_null(self.result(), self.pos)))
- code.put_gotref(self.py_result())
+ if self.type.is_pyobject:
+ code.putln(
+ "%s = PyComplex_FromDoubles(0.0, %r); %s" % (
+ self.result(),
+ float(self.value),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+ else:
+ self.c99_complex = code.globalstate.directives['c99_complex']
error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
if to_py and not from_py:
if (self.operand.type.to_py_function and
- self.operand.type.create_convert_utility_code(env)):
+ self.operand.type.create_to_py_utility_code(env)):
self.result_ctype = py_object_type
self.operand = self.operand.coerce_to_pyobject(env)
else:
self.type = self.compute_c_result_type(type1, type2)
if not self.type:
self.type_error()
+ return
+ self.infix = not self.type.is_complex or env.directives['c99_complex']
+ if not self.infix:
+ self.operand1 = self.operand1.coerce_to(self.type, env)
+ self.operand2 = self.operand2.coerce_to(self.type, env)
def compute_c_result_type(self, type1, type2):
if self.c_types_okay(type1, type2):
and (type2.is_numeric or type2.is_enum)
def calculate_result_code(self):
- return "(%s %s %s)" % (
- self.operand1.result(),
- self.operator,
- self.operand2.result())
+ if self.infix:
+ return "(%s %s %s)" % (
+ self.operand1.result(),
+ self.operator,
+ self.operand2.result())
+ else:
+ return "%s(%s, %s)" % (
+ self.type.binop(self.operator),
+ self.operand1.result(),
+ self.operand2.result())
def py_operation_function(self):
return self.py_functions[self.operator]
def analyse_c_operation(self, env):
NumBinopNode.analyse_c_operation(self, env)
- if self.operand1.type.is_float or self.operand2.type.is_float:
+ if self.type.is_complex:
+ error(self.pos, "complex powers not yet supported")
+ self.pow_func = "<error>"
+ elif self.type.is_float:
self.pow_func = "pow"
else:
self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_')
self.type = py_object_type
self.gil_check(env)
self.is_temp = 1
- if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env):
+ if not arg.type.to_py_function or not arg.type.create_to_py_utility_code(env):
error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type)
CoercionNode.__init__(self, arg)
self.type = result_type
self.is_temp = 1
- if not result_type.from_py_function:
+ if not result_type.from_py_function and not result_type.create_from_py_utility_code(env):
error(arg.pos,
"Cannot convert Python object to '%s'" % result_type)
if self.type.is_string and self.arg.is_ephemeral():
self.arg.py_result(),
code.error_goto_if_neg(self.result(), self.pos)))
+class CoerceToComplexNode(CoercionNode):
+
+ def __init__(self, arg, dst_type, env):
+ if arg.type.is_complex:
+ arg = arg.coerce_to_simple(env)
+ self.type = dst_type
+ CoercionNode.__init__(self, arg)
+ dst_type.create_declaration_utility_code(env)
+
+ def calculate_result_code(self):
+ if self.arg.type.is_complex:
+ real_part = "__Pyx_REAL_PART(%s)" % self.arg.result()
+ imag_part = "__Pyx_IMAG_PART(%s)" % self.arg.result()
+ else:
+ real_part = self.arg.result()
+ imag_part = "0"
+ return "%s(%s, %s)" % (
+ self.type.from_parts,
+ real_part,
+ imag_part)
+
+ def generate_result_code(self, code):
+ pass
class CoerceToTempNode(CoercionNode):
# This node is used to force the result of another node
code.putln("#include <math.h>")
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code)
+ if env.directives['c99_complex']:
+ code.putln("#ifndef _Complex_I")
+ code.putln("#include <complex.h>")
+ code.putln("#endif")
+ code.putln("#define __PYX_USE_C99_COMPLEX defined(_Complex_I)")
code.putln('')
code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations)
if not type.is_numeric or type.is_complex:
error(self.pos, "can only complexify c numeric types")
type = PyrexTypes.CComplexType(type)
+ type.create_declaration_utility_code(env)
if type:
return type
else:
error(arg.pos, "Non-default argument following default argument")
elif not arg.is_self_arg:
positional_args.append(arg)
+ if arg.type.from_py_function is None:
+ arg.type.create_from_py_utility_code(env)
self.generate_tuple_and_keyword_parsing_code(
positional_args, kw_only_args, end_label, code)
if c_op == "//":
c_op = "/"
elif c_op == "**":
- if self.lhs.type.is_int and self.rhs.type.is_int:
- error(self.pos, "** with two C int types is ambiguous")
- else:
- error(self.pos, "No C inplace power operator")
+ error(self.pos, "No C inplace power operator")
+ elif self.lhs.type.is_complex and not code.globalstate.directives['c99_complex']:
+ error(self.pos, "Inplace operators not implemented for complex types.")
+
# have to do assignment directly to avoid side-effects
if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
'cdivision_warnings': False,
'always_allow_keywords': False,
'wraparound' : True,
- 'c99_complex' : False,
- 'a': 4,
+ 'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
}
# Override types possibilities above, if needed
exception_value = None
exception_check = 1
- def create_convert_utility_code(self, env):
+ def create_to_py_utility_code(self, env):
+ return True
+
+ def create_from_py_utility_code(self, env):
return True
def error_condition(self, result_code):
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
def __init__(self, real_type):
self.real_type = real_type
CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed)
- self.from_py_function = "__pyx_PyObject_As_" + self.specalization_name()
+ self.binops = {}
def __cmp__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
else:
return 1
+ def __hash__(self):
+ return ~hash(self.real_type)
+
def sign_and_name(self):
- return self.real_type.sign_and_name() + " _Complex"
+ return Naming.type_prefix + self.real_type.specalization_name() + "_complex"
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 error_type)
- def create_convert_utility_code(self, env):
- self.real_type.create_convert_utility_code(env)
- env.use_utility_code(complex_generic_utility_code)
+ def create_declaration_utility_code(self, env):
+ if not hasattr(self, 'from_parts'):
+ self.from_parts = "%s_from_parts" % self.specalization_name()
+ env.use_utility_code(complex_generic_utility_code)
+ env.use_utility_code(
+ complex_arithmatic_utility_code.specialize(self,
+ math_h_modifier = self.real_type.math_h_modifier,
+ real_type = self.real_type.declaration_code('')))
+ return True
+
+ def create_from_py_utility_code(self, env):
+ self.real_type.create_from_py_utility_code(env)
env.use_utility_code(
- complex_utility_code.specialize(self,
- real_type=self.real_type.declaration_code(''),
- type_convert=self.real_type.from_py_function))
+ complex_conversion_utility_code.specialize(self,
+ math_h_modifier = self.real_type.math_h_modifier,
+ real_type = self.real_type.declaration_code(''),
+ type_convert = self.real_type.from_py_function))
+ self.from_py_function = "__pyx_PyObject_As_" + self.specalization_name()
return True
+
+ def binop(self, op):
+ try:
+ return self.binops[op]
+ except KeyError:
+ if op in "+-*/":
+ from ExprNodes import compile_time_binary_operators
+ op_name = compile_time_binary_operators[op].__name__
+ self.binops[op] = func_name = "%s_%s" % (self.specalization_name(), op_name)
+ return func_name
+ else:
+ error("Binary '%s' not supported in for %s" % (op, self))
+ return "<error>"
-complex_utility_code = UtilityCode(
+complex_generic_utility_code = UtilityCode(
+proto="""
+#if __PYX_USE_C99_COMPLEX
+ #define __Pyx_REAL_PART(z) __real__(z)
+ #define __Pyx_IMAG_PART(z) __imag__(z)
+#else
+ #define __Pyx_REAL_PART(z) ((z).real)
+ #define __Pyx_IMAG_PART(z) ((z).imag)
+#endif
+
+#define __pyx_PyObject_from_complex(z) PyComplex_FromDoubles((double)__Pyx_REAL_PART(z), (double)__Pyx_IMAG_PART(z))
+""")
+
+complex_conversion_utility_code = UtilityCode(
proto="""
-static INLINE %(type)s __pyx_%(type_name)s_from_parts(%(real_type)s real, %(real_type)s imag); /* proto */
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o); /* proto */
""",
impl="""
-static INLINE %(type)s __pyx_%(type_name)s_from_parts(%(real_type)s real, %(real_type)s imag) {
- %(type)s z;
- __real__(z) = real;
- __imag__(z) = imag;
- return z;
-}
-
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o) {
if (PyComplex_Check(o)) {
- return __pyx_%(type_name)s_from_parts(
+ return %(type_name)s_from_parts(
(%(real_type)s)((PyComplexObject *)o)->cval.real,
(%(real_type)s)((PyComplexObject *)o)->cval.imag);
}
else {
- return __pyx_%(type_name)s_from_parts(%(type_convert)s(o), 0);
+ return %(type_name)s_from_parts(%(type_convert)s(o), 0);
}
}
""")
-complex_generic_utility_code = UtilityCode(
+complex_arithmatic_utility_code = UtilityCode(
proto="""
-#define __pyx_PyObject_from_complex(z) PyComplex_FromDoubles((double)__real__(z), (double)__imag__(z))
+#if __PYX_USE_C99_COMPLEX
+
+ typedef %(real_type)s _Complex %(type_name)s;
+ #define %(type_name)s_from_parts(x, y) ((x) + (y)*(%(type)s)_Complex_I)
+
+ #define %(type_name)s_is_zero(a) ((a) == 0)
+ #define %(type_name)s_add(a, b) ((a)+(b))
+ #define %(type_name)s_sub(a, b) ((a)-(b))
+ #define %(type_name)s_mul(a, b) ((a)*(b))
+ #define %(type_name)s_div(a, b) ((a)/(b))
+ #define %(type_name)s_neg(a) (-(a))
+
+#else
+
+ typedef struct { %(real_type)s real, imag; } %(type_name)s;
+ #define %(type_name)s_from_parts(x, y) ((%(type_name)s){(%(real_type)s)x, (%(real_type)s)y})
+
+ static INLINE int %(type_name)s_is_zero(%(type)s a) {
+ return (a.real == 0) & (a.imag == 0);
+ }
+
+ static INLINE %(type)s %(type_name)s_add(%(type)s a, %(type)s b) {
+ %(type)s z;
+ z.real = a.real + b.real;
+ z.imag = a.imag + b.imag;
+ return z;
+ }
+
+ static INLINE %(type)s %(type_name)s_sub(%(type)s a, %(type)s b) {
+ %(type)s z;
+ z.real = a.real - b.real;
+ z.imag = a.imag - b.imag;
+ return z;
+ }
+
+ static INLINE %(type)s %(type_name)s_mul(%(type)s a, %(type)s b) {
+ %(type)s z;
+ z.real = a.real * b.real - a.imag * b.imag;
+ z.imag = a.real * b.imag + a.imag * b.real;
+ return z;
+ }
+
+ static INLINE %(type)s %(type_name)s_div(%(type)s a, %(type)s b) {
+ %(type)s z;
+ %(real_type)s denom = b.real*b.real + b.imag*b.imag;
+ z.real = (a.real * b.real + a.imag * b.imag) / denom;
+ z.imag = (a.imag * b.real - a.real * b.imag) / denom;
+ return z;
+ }
+
+ static INLINE %(type)s %(type_name)s_neg(%(type)s a) {
+ %(type)s z;
+ z.real = -a.real;
+ z.imag = -a.imag;
+ return z;
+ }
+
+#endif
""")
self._convert_code = None
self.packed = packed
- def create_convert_utility_code(self, env):
+ def create_to_py_utility_code(self, env):
if env.outer_scope is None:
return False
if self._convert_code is None:
code.putln("PyObject* member;")
code.putln("res = PyDict_New(); if (res == NULL) return NULL;")
for member in self.scope.var_entries:
- if member.type.to_py_function and member.type.create_convert_utility_code(env):
+ if member.type.to_py_function and member.type.create_to_py_utility_code(env):
interned_name = env.get_string_const(member.name, identifier=True)
env.add_py_string(interned_name)
code.putln("member = %s(s.%s); if (member == NULL) goto bad;" % (
to_py_function = "dummy"
from_py_function = "dummy"
- def create_convert_utility_code(self, env):
+ 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,
c_double_type = CFloatType(8, "T_DOUBLE")
c_longdouble_type = CFloatType(9, math_h_modifier='l')
+c_double_complex_type = CComplexType(c_double_type)
+
c_null_ptr_type = CNullPtrType(c_void_type)
c_char_array_type = CCharArrayType(None)
c_char_ptr_type = CCharPtrType()
if type1 == type2:
return type1
if type1.is_complex:
- return CComplexType(widest_numeric_type(type1.real_type, type2))
+ 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: