Commit 39d60c71 authored by Stefan Behnel's avatar Stefan Behnel

merged in latest cython-devel (with minor merge fixes)

parents cad41704 137545fd
......@@ -132,6 +132,7 @@ class CodeWriter(TreeVisitor):
def visit_IntNode(self, node):
self.put(node.value)
# FIXME: represent string nodes correctly
def visit_StringNode(self, node):
value = node.value
if value.encoding is not None:
......
from Cython.Compiler.Visitor import VisitorTransform, ScopeTrackingTransform, TreeVisitor
from Nodes import StatListNode, SingleAssignmentNode, CFuncDefNode
from ExprNodes import (DictNode, DictItemNode, NameNode, UnicodeNode, NoneNode,
ExprNode, AttributeNode, ModuleRefNode, DocstringRefNode)
from ExprNodes import DictNode, DictItemNode, NameNode, UnicodeNode, NoneNode, \
ExprNode, AttributeNode, ModuleRefNode, DocstringRefNode
from PyrexTypes import py_object_type
from Builtin import dict_type
from StringEncoding import EncodedString
......@@ -10,6 +10,8 @@ import Naming
class AutoTestDictTransform(ScopeTrackingTransform):
# Handles autotestdict directive
blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__']
def visit_ModuleNode(self, node):
self.scope_type = 'module'
self.scope_node = node
......@@ -62,6 +64,12 @@ class AutoTestDictTransform(ScopeTrackingTransform):
parent = ModuleRefNode(pos)
name = node.entry.name
elif self.scope_type in ('pyclass', 'cclass'):
if isinstance(node, CFuncDefNode):
name = node.py_func.name
else:
name = node.name
if self.scope_type == 'cclass' and name in self.blacklist:
return node
mod = ModuleRefNode(pos)
if self.scope_type == 'pyclass':
clsname = self.scope_node.name
......
......@@ -3,9 +3,7 @@ from Cython.Compiler.Nodes import DefNode, CFuncDefNode
from Cython.Compiler.Errors import CompileError
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler import Options
from Cython.Compiler import PyrexTypes
from Cython.Compiler import PyrexTypes, ExprNodes
class EmbedSignature(CythonTransform):
......@@ -16,15 +14,26 @@ class EmbedSignature(CythonTransform):
self.class_node = None
def _fmt_arg_defv(self, arg):
if not arg.default:
default_val = arg.default
if not default_val:
return None
try:
denv = self.denv # XXX
ctval = arg.default.compile_time_value(self.denv)
return '%r' % ctval
ctval = default_val.compile_time_value(self.denv)
repr_val = '%r' % ctval
if isinstance(default_val, ExprNodes.UnicodeNode):
if repr_val[:1] != 'u':
return u'u%s' % repr_val
elif isinstance(default_val, ExprNodes.BytesNode):
if repr_val[:1] != 'b':
return u'b%s' % repr_val
elif isinstance(default_val, ExprNodes.StringNode):
if repr_val[:1] in ('u', 'b'):
repr_val[1:]
return repr_val
except Exception:
try:
return arg.default.name # XXX
return default_val.name # XXX
except AttributeError:
return '<???>'
......
......@@ -392,13 +392,15 @@ def init_builtins():
init_builtin_funcs()
init_builtin_types()
init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, bytes_type, unicode_type, type_type
global list_type, tuple_type, dict_type, set_type, type_type
global bytes_type, str_type, unicode_type
type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type
dict_type = builtin_scope.lookup('dict').type
set_type = builtin_scope.lookup('set').type
bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type
init_builtins()
......@@ -39,12 +39,12 @@ Options:
--line-directives Produce #line directives pointing to the .pyx source
--cplus Output a c++ rather than c file.
--embed Embed the Python interpreter in a main() method.
--directive <name>=<value>[,<name=value,...] Overrides a compiler directive
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
"""
#The following experimental options are supported only on MacOSX:
# -C, --compile Compile generated .c file to .o file
# -X, --link Link .o file to produce extension module (implies -C)
# --link Link .o file to produce extension module (implies -C)
# -+, --cplus Use C++ compiler for compiling and linking
# Additional .o files to link may be supplied when using -X."""
......@@ -81,11 +81,7 @@ def parse_command_line(args):
options.use_listing_file = 1
elif option in ("-C", "--compile"):
options.c_only = 0
elif option in ("-X", "--link"):
if option == "-X":
print >>sys.stderr, "Deprecation warning: The -X command line switch will be changed to a"
print >>sys.stderr, "shorthand for --directive in Cython 0.12. Please use --link instead."
print >>sys.stderr
elif option in ("--link"):
options.c_only = 0
options.obj_only = 0
elif option in ("-+", "--cplus"):
......@@ -126,7 +122,7 @@ def parse_command_line(args):
options.emit_linenums = True
elif option in ("-X", "--directive"):
try:
options.compiler_directives = Options.parse_option_list(pop_arg())
options.compiler_directives = Options.parse_directive_list(pop_arg())
except ValueError, e:
sys.stderr.write("Error in compiler directive: %s\n" % e.message)
sys.exit(1)
......
......@@ -289,7 +289,8 @@ class PyObjectConst(object):
possible_unicode_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
possible_bytes_identifier = re.compile(r"(?![0-9])\w+$".encode('ASCII')).match
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
nice_identifier = re.compile('^[a-zA-Z0-9_]+$').match
find_alphanums = re.compile('([a-zA-Z0-9]+)').findall
class StringConst(object):
"""Global info about a C string constant held by GlobalState.
......@@ -304,19 +305,31 @@ class StringConst(object):
self.escaped_value = StringEncoding.escape_byte_string(byte_string)
self.py_strings = None
def get_py_string_const(self, encoding, identifier=None):
def get_py_string_const(self, encoding, identifier=None, is_str=False):
py_strings = self.py_strings
text = self.text
if encoding is not None:
encoding = encoding.upper()
key = (bool(identifier), encoding)
is_str = bool(identifier or is_str)
is_unicode = encoding is None and not is_str
if encoding is None:
# unicode string
encoding_key = None
else:
# bytes or str
encoding = encoding.lower()
if encoding in ('utf8', 'utf-8', 'ascii', 'usascii', 'us-ascii'):
encoding = None
encoding_key = None
else:
encoding_key = ''.join(find_alphanums(encoding))
key = (is_str, is_unicode, encoding_key)
if py_strings is not None and key in py_strings:
py_string = py_strings[key]
else:
if py_strings is None:
self.py_strings = {}
is_unicode = encoding is None
if identifier:
intern = True
elif identifier is None:
......@@ -330,14 +343,13 @@ class StringConst(object):
prefix = Naming.interned_str_prefix
else:
prefix = Naming.py_const_prefix
pystring_cname = "%s%s%s_%s" % (
pystring_cname = "%s%s_%s" % (
prefix,
is_unicode and 'u' or 'b',
identifier and 'i' or '',
(is_str and 's') or (is_unicode and 'u') or 'b',
self.cname[len(Naming.const_prefix):])
py_string = PyStringConst(
pystring_cname, is_unicode, bool(identifier), intern)
pystring_cname, encoding, is_unicode, is_str, intern)
self.py_strings[key] = py_string
return py_string
......@@ -346,14 +358,16 @@ class PyStringConst(object):
"""Global info about a Python string constant held by GlobalState.
"""
# cname string
# unicode boolean
# encoding string
# intern boolean
# identifier boolean
# is_unicode boolean
# is_str boolean
def __init__(self, cname, is_unicode, identifier=False, intern=False):
def __init__(self, cname, encoding, is_unicode, is_str=False, intern=False):
self.cname = cname
self.identifier = identifier
self.unicode = is_unicode
self.encoding = encoding
self.is_str = is_str
self.is_unicode = is_unicode
self.intern = intern
def __lt__(self, other):
......@@ -393,7 +407,6 @@ class GlobalState(object):
code_layout = [
'h_code',
'complex_numbers_utility_code',
'utility_code_proto_before_types',
'type_declarations',
'utility_code_proto',
......@@ -511,6 +524,11 @@ class GlobalState(object):
w.putln("}")
w.exit_cfunc_scope()
if Options.generate_cleanup_code:
w = self.parts['cleanup_globals']
w.putln("}")
w.exit_cfunc_scope()
if Options.generate_cleanup_code:
w = self.parts['cleanup_module']
w.putln("}")
......@@ -545,12 +563,15 @@ class GlobalState(object):
c = self.new_string_const(text, byte_string)
return c
def get_py_string_const(self, text, identifier=None):
def get_py_string_const(self, text, identifier=None, is_str=False):
# return a Python string constant, creating a new one if necessary
c_string = self.get_string_const(text)
py_string = c_string.get_py_string_const(text.encoding, identifier)
py_string = c_string.get_py_string_const(text.encoding, identifier, is_str)
return py_string
def get_interned_identifier(self, text):
return self.get_py_string_const(text, identifier=True)
def new_string_const(self, text, byte_string):
cname = self.new_string_const_cname(byte_string)
c = StringConst(cname, text, byte_string)
......@@ -577,7 +598,7 @@ class GlobalState(object):
return self.new_const_cname()
if len(value) < 20 and nice_identifier(value):
return "%s%s" % (Naming.const_prefix, value)
return "%s_%s" % (Naming.const_prefix, value)
else:
return self.new_const_cname()
......@@ -596,7 +617,7 @@ class GlobalState(object):
def add_cached_builtin_decl(self, entry):
if Options.cache_builtins:
if self.should_declare(entry.cname, entry):
interned_cname = self.get_py_string_const(entry.name, True).cname
interned_cname = self.get_interned_identifier(entry.name).cname
self.put_pyobject_decl(entry)
w = self.parts['cached_builtins']
w.putln('%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
......@@ -644,18 +665,26 @@ class GlobalState(object):
w.putln("static __Pyx_StringTabEntry %s[] = {" %
Naming.stringtab_cname)
for c_cname, _, py_string in py_strings:
if not py_string.is_str or not py_string.encoding or \
py_string.encoding in ('ASCII', 'USASCII', 'US-ASCII',
'UTF8', 'UTF-8'):
encoding = '0'
else:
encoding = '"%s"' % py_string.encoding.lower()
decls_writer.putln(
"static PyObject *%s;" % py_string.cname)
w.putln(
"{&%s, %s, sizeof(%s), %d, %d, %d}," % (
"{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
py_string.cname,
c_cname,
c_cname,
py_string.unicode,
py_string.intern,
py_string.identifier
encoding,
py_string.is_unicode,
py_string.is_str,
py_string.intern
))
w.putln("{0, 0, 0, 0, 0, 0}")
w.putln("{0, 0, 0, 0, 0, 0, 0}")
w.putln("};")
init_globals = self.parts['init_globals']
......@@ -718,8 +747,9 @@ class GlobalState(object):
u'*/', u'*[inserted by cython to avoid comment closer]/'
).replace(
u'/*', u'/[inserted by cython to avoid comment start]*'
).encode('ASCII', 'replace').decode('ASCII')
for line in source_desc.get_lines()]
)
for line in source_desc.get_lines(encoding='ASCII',
error_handling='ignore')]
if len(F) == 0: F.append(u'')
self.input_file_contents[source_desc] = F
return F
......@@ -889,8 +919,8 @@ class CCodeWriter(object):
def get_string_const(self, text):
return self.globalstate.get_string_const(text).cname
def get_py_string_const(self, text, identifier=None):
return self.globalstate.get_py_string_const(text, identifier).cname
def get_py_string_const(self, text, identifier=None, is_str=False):
return self.globalstate.get_py_string_const(text, identifier, is_str).cname
def get_argument_default_const(self, type):
return self.globalstate.get_py_const(type).cname
......@@ -899,7 +929,7 @@ class CCodeWriter(object):
return self.get_py_string_const(text)
def intern_identifier(self, text):
return self.get_py_string_const(text, True)
return self.get_py_string_const(text, identifier=True)
# code generation
......@@ -1244,10 +1274,10 @@ class CCodeWriter(object):
return self.globalstate.lookup_filename(filename)
def put_setup_refcount_context(self, name):
self.putln('__Pyx_SetupRefcountContext("%s");' % name)
self.putln('__Pyx_RefNannySetupContext("%s");' % name)
def put_finish_refcount_context(self):
self.putln("__Pyx_FinishRefcountContext();")
self.putln("__Pyx_RefNannyFinishContext();")
def put_trace_call(self, name, pos):
self.putln('__Pyx_TraceCall("%s", %s[%s], %s);' % (name, Naming.filetable_cname, self.lookup_filename(pos[0]), pos[1]));
......
......@@ -12,8 +12,9 @@ import Naming
import Nodes
from Nodes import Node
import PyrexTypes
from PyrexTypes import py_object_type, c_long_type, typecast, error_type
from Builtin import list_type, tuple_type, set_type, dict_type, unicode_type, bytes_type
from PyrexTypes import py_object_type, c_long_type, typecast, error_type, unspecified_type
from Builtin import list_type, tuple_type, set_type, dict_type, \
unicode_type, str_type, bytes_type, type_type
import Builtin
import Symtab
import Options
......@@ -32,6 +33,22 @@ class NotConstant(object): pass # just for the name
not_a_constant = NotConstant()
constant_value_not_set = object()
# error messages when coercing from key[0] to key[1]
find_coercion_error = {
# string related errors
(Builtin.unicode_type, Builtin.bytes_type) : "Cannot convert Unicode string to 'bytes' implicitly, encoding required.",
(Builtin.unicode_type, Builtin.str_type) : "Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.",
(Builtin.unicode_type, PyrexTypes.c_char_ptr_type) : "Unicode objects do not support coercion to C types.",
(Builtin.bytes_type, Builtin.unicode_type) : "Cannot convert 'bytes' object to unicode implicitly, decoding required",
(Builtin.bytes_type, Builtin.str_type) : "Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.",
(Builtin.str_type, Builtin.unicode_type) : "str objects do not support coercion to unicode, use a unicode string literal instead (u'')",
(Builtin.str_type, Builtin.bytes_type) : "Cannot convert 'str' to 'bytes' implicitly. This is not portable.",
(Builtin.str_type, PyrexTypes.c_char_ptr_type) : "'str' objects do not support coercion to C types (use 'bytes'?).",
(PyrexTypes.c_char_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
(PyrexTypes.c_uchar_ptr_type, Builtin.unicode_type) : "Cannot convert 'char*' to unicode implicitly, decoding required",
}.get
class ExprNode(Node):
# subexprs [string] Class var holding names of subexpr node attrs
# type PyrexType Type of the result
......@@ -44,11 +61,13 @@ class ExprNode(Node):
# saved_subexpr_nodes
# [ExprNode or [ExprNode or None] or None]
# Cached result of subexpr_nodes()
# use_managed_ref boolean use ref-counted temps/assignments/etc.
result_ctype = None
type = None
temp_code = None
old_temp = None # error checker for multiple frees etc.
use_managed_ref = True # can be set by optimisation transforms
# The Analyse Expressions phase for expressions is split
# into two sub-phases:
......@@ -307,6 +326,27 @@ class ExprNode(Node):
temp_bool = bool.coerce_to_temp(env)
return temp_bool
# --------------- Type Inference -----------------
def type_dependencies(self, env):
# Returns the list of entries whose types must be determined
# before the type of self can be infered.
if hasattr(self, 'type') and self.type is not None:
return ()
return sum([node.type_dependencies(env) for node in self.subexpr_nodes()], ())
def infer_type(self, env):
# Attempt to deduce the type of self.
# Differs from analyse_types as it avoids unnecessary
# analysis of subexpressions, but can assume everything
# in self.type_dependencies() has been resolved.
if hasattr(self, 'type') and self.type is not None:
return self.type
elif hasattr(self, 'entry') and self.entry is not None:
return self.entry.type
else:
self.not_implemented("infer_type")
# --------------- Type Analysis ------------------
def analyse_as_module(self, env):
......@@ -375,13 +415,13 @@ class ExprNode(Node):
def allocate_temp_result(self, code):
if self.temp_code:
raise RuntimeError("Temp allocated multiple times")
raise RuntimeError("Temp allocated multiple times in %r: %r" % (self.__class__.__name__, self.pos))
type = self.type
if not type.is_void:
if type.is_pyobject:
type = PyrexTypes.py_object_type
self.temp_code = code.funcstate.allocate_temp(
type, manage_ref=True)
type, manage_ref=self.use_managed_ref)
else:
self.temp_code = None
......@@ -495,6 +535,9 @@ class ExprNode(Node):
src_is_py_type = src_type.is_pyobject
dst_is_py_type = dst_type.is_pyobject
if self.check_for_coercion_error(dst_type):
return self
if dst_type.is_pyobject:
if not src.type.is_pyobject:
src = CoerceToPyTypeNode(src, env)
......@@ -505,18 +548,31 @@ class ExprNode(Node):
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']):
and dst_type.assignable_from(src_type)):
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 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))
self.fail_assignment(dst_type)
return src
def fail_assignment(self, dst_type):
error(self.pos, "Cannot assign type '%s' to '%s'" % (self.type, dst_type))
def check_for_coercion_error(self, dst_type, fail=False, default=None):
if fail and not default:
default = "Cannot assign type '%(FROM)s' to '%(TO)s'"
message = find_coercion_error((self.type, dst_type), default)
if message is not None:
error(self.pos, message % {'FROM': self.type, 'TO': dst_type})
return True
if fail:
self.fail_assignment(dst_type)
return True
return False
def coerce_to_pyobject(self, env):
return self.coerce_to(PyrexTypes.py_object_type, env)
......@@ -746,7 +802,11 @@ class FloatNode(ConstNode):
return strval
class StringNode(ConstNode):
class BytesNode(ConstNode):
# A char* or bytes literal
#
# value BytesLiteral
type = PyrexTypes.c_char_ptr_type
def compile_time_value(self, denv):
......@@ -764,6 +824,9 @@ class StringNode(ConstNode):
if isinstance(sizeof_node, SizeofTypeNode):
return sizeof_node.arg_type
def can_coerce_to_char_literal(self):
return len(self.value) == 1
def coerce_to(self, dst_type, env):
if dst_type == PyrexTypes.c_char_ptr_type:
self.type = PyrexTypes.c_char_ptr_type
......@@ -773,31 +836,33 @@ class StringNode(ConstNode):
return CastNode(self, PyrexTypes.c_uchar_ptr_type)
if dst_type.is_int:
if not self.type.is_pyobject and len(self.value) == 1:
return CharNode(self.pos, value=self.value)
else:
error(self.pos, "Only single-character byte strings can be coerced into ints.")
if not self.can_coerce_to_char_literal():
error(self.pos, "Only single-character strings can be coerced into ints.")
return self
# Arrange for a Python version of the string to be pre-allocated
# when coercing to a Python type.
if dst_type.is_pyobject and not self.type.is_pyobject:
warn_once(self.pos, "String literals will no longer be Py3 bytes in Cython 0.12.", 1)
return CharNode(self.pos, value=self.value)
node = self
if not self.type.is_pyobject:
if dst_type in (py_object_type, Builtin.bytes_type):
node = self.as_py_string_node(env)
elif dst_type.is_pyobject:
self.fail_assignment(dst_type)
return self
else:
node = self
elif dst_type.is_pyobject and dst_type is not py_object_type:
self.check_for_coercion_error(dst_type, fail=True)
return self
# 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 ConstNode.coerce_to(node, dst_type, env)
def as_py_string_node(self, env):
# Return a new StringNode with the same value as this node
# Return a new BytesNode with the same value as this node
# but whose type is a Python type instead of a C type.
if self.value.encoding is None:
py_type = Builtin.unicode_type
else:
py_type = Builtin.bytes_type
return StringNode(self.pos, value = self.value, type = py_type)
return BytesNode(self.pos, value = self.value, type = Builtin.bytes_type)
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
......@@ -813,20 +878,24 @@ class StringNode(ConstNode):
class UnicodeNode(PyConstNode):
# A Python unicode object
#
# value EncodedString
type = unicode_type
def coerce_to(self, dst_type, env):
if dst_type.is_pyobject:
return self
else:
if dst_type is self.type:
pass
elif not dst_type.is_pyobject:
error(self.pos, "Unicode objects do not support coercion to C types.")
elif dst_type is not py_object_type:
if not self.check_for_coercion_error(dst_type):
self.fail_assignment(dst_type)
return self
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
self.result_code = code.get_py_string_const(self.value)
else:
self.result_code = code.get_string_const(self.value)
def calculate_result_code(self):
return self.result_code
......@@ -835,16 +904,41 @@ class UnicodeNode(PyConstNode):
return self.value
class IdentifierStringNode(ConstNode):
# A Python string that behaves like an identifier, e.g. for
# keyword arguments in a call, or for imported names
type = PyrexTypes.py_object_type
class StringNode(PyConstNode):
# A Python str object, i.e. a byte string in Python 2.x and a
# unicode string in Python 3.x
#
# value BytesLiteral or EncodedString
# is_identifier boolean
type = str_type
is_identifier = False
def coerce_to(self, dst_type, env):
if dst_type is not py_object_type and dst_type is not str_type:
# if dst_type is Builtin.bytes_type:
# # special case: bytes = 'str literal'
# return BytesNode(self.pos, value=self.value)
if not dst_type.is_pyobject:
return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env)
self.check_for_coercion_error(dst_type, fail=True)
# this will be a unicode string in Py3, so make sure we can decode it
if not self.is_identifier:
encoding = self.value.encoding or 'UTF-8'
try:
self.value.decode(encoding)
except UnicodeDecodeError:
error(self.pos, "String decoding as '%s' failed. Consider using a byte string or unicode string explicitly, or adjust the source code encoding." % encoding)
return self
def can_coerce_to_char_literal(self):
return not self.is_identifier and len(self.value) == 1
def generate_evaluation_code(self, code):
if self.type.is_pyobject:
self.result_code = code.get_py_string_const(self.value, True)
else:
self.result_code = code.get_string_const(self.value)
self.result_code = code.get_py_string_const(
self.value, identifier=self.is_identifier, is_str=True)
def get_constant_c_result_code(self):
return None
......@@ -852,12 +946,23 @@ class IdentifierStringNode(ConstNode):
def calculate_result_code(self):
return self.result_code
def compile_time_value(self, env):
return self.value
class IdentifierStringNode(StringNode):
# A special str value that represents an identifier (bytes in Py2,
# unicode in Py3).
is_identifier = True
class LongNode(AtomicExprNode):
# Python long integer literal
#
# value string
type = py_object_type
def calculate_constant_result(self):
self.constant_result = long(self.value)
......@@ -865,7 +970,6 @@ class LongNode(AtomicExprNode):
return long(self.value)
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = 1
gil_message = "Constructing Python long int"
......@@ -911,8 +1015,6 @@ class ImagNode(AtomicExprNode):
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))
......@@ -924,8 +1026,6 @@ class ImagNode(AtomicExprNode):
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']
......@@ -954,6 +1054,27 @@ class NameNode(AtomicExprNode):
create_analysed_rvalue = staticmethod(create_analysed_rvalue)
def type_dependencies(self, env):
if self.entry is None:
self.entry = env.lookup(self.name)
if self.entry is not None and self.entry.type.is_unspecified:
return (self.entry,)
else:
return ()
def infer_type(self, env):
if self.entry is None:
self.entry = env.lookup(self.name)
if self.entry is None:
return py_object_type
elif (self.entry.type.is_extension_type or self.entry.type.is_builtin_type) and \
self.name == self.entry.type.name:
# Unfortunately the type attribute of type objects
# is used for the pointer to the type the represent.
return type_type
else:
return self.entry.type
def compile_time_value(self, denv):
try:
return denv.lookup(self.name)
......@@ -1023,7 +1144,11 @@ class NameNode(AtomicExprNode):
if not self.entry:
self.entry = env.lookup_here(self.name)
if not self.entry:
self.entry = env.declare_var(self.name, py_object_type, self.pos)
if env.directives['infer_types']:
type = unspecified_type
else:
type = py_object_type
self.entry = env.declare_var(self.name, type, self.pos)
env.control_flow.set_state(self.pos, (self.name, 'initalized'), True)
env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
if self.entry.is_declared_generic:
......@@ -1223,14 +1348,15 @@ class NameNode(AtomicExprNode):
self.generate_acquire_buffer(rhs, code)
if self.type.is_pyobject:
rhs.make_owned_reference(code)
#print "NameNode.generate_assignment_code: to", self.name ###
#print "...from", rhs ###
#print "...LHS type", self.type, "ctype", self.ctype() ###
#print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
if self.use_managed_ref:
rhs.make_owned_reference(code)
if entry.is_cglobal:
code.put_gotref(self.py_result())
if not self.lhs_of_first_assignment:
if self.use_managed_ref and not self.lhs_of_first_assignment:
if entry.is_local and not Options.init_local_none:
initalized = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
if initalized is True:
......@@ -1239,6 +1365,7 @@ class NameNode(AtomicExprNode):
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
if self.use_managed_ref:
if entry.is_cglobal or entry.in_closure:
code.put_giveref(rhs.py_result())
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
......@@ -1294,12 +1421,13 @@ class BackquoteNode(ExprNode):
#
# arg ExprNode
type = py_object_type
subexprs = ['arg']
def analyse_types(self, env):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Backquote expression"
......@@ -1322,9 +1450,11 @@ class ImportNode(ExprNode):
# Implements result =
# __import__(module_name, globals(), None, name_list)
#
# module_name IdentifierStringNode dotted name of module
# module_name StringNode dotted name of module
# name_list ListNode or None list of names to be imported
type = py_object_type
subexprs = ['module_name', 'name_list']
def analyse_types(self, env):
......@@ -1333,7 +1463,6 @@ class ImportNode(ExprNode):
if self.name_list:
self.name_list.analyse_types(env)
self.name_list.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
env.use_utility_code(import_utility_code)
......@@ -1363,12 +1492,13 @@ class IteratorNode(ExprNode):
#
# sequence ExprNode
type = py_object_type
subexprs = ['sequence']
def analyse_types(self, env):
self.sequence.analyse_types(env)
self.sequence = self.sequence.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Iterating over Python object"
......@@ -1420,10 +1550,11 @@ class NextNode(AtomicExprNode):
#
# iterator ExprNode
type = py_object_type
def __init__(self, iterator, env):
self.pos = iterator.pos
self.iterator = iterator
self.type = py_object_type
self.is_temp = 1
def generate_result_code(self, code):
......@@ -1476,9 +1607,10 @@ class ExcValueNode(AtomicExprNode):
# of an ExceptClauseNode to fetch the current
# exception value.
type = py_object_type
def __init__(self, pos, env):
ExprNode.__init__(self, pos)
self.type = py_object_type
def set_var(self, var):
self.var = var
......@@ -1544,6 +1676,25 @@ class PyTempNode(TempNode):
def __init__(self, pos, env):
TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
class RawCNameExprNode(ExprNode):
subexprs = []
def __init__(self, pos, type=None):
self.pos = pos
self.type = type
def analyse_types(self, env):
return self.type
def set_cname(self, cname):
self.cname = cname
def result(self):
return self.cname
def generate_result_code(self, code):
pass
#-------------------------------------------------------------------
#
......@@ -1594,6 +1745,19 @@ class IndexNode(ExprNode):
return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
return None
def type_dependencies(self, env):
return self.base.type_dependencies(env)
def infer_type(self, env):
if isinstance(self.base, (StringNode, UnicodeNode)): # FIXME: BytesNode?
return py_object_type
base_type = self.base.infer_type(env)
if base_type.is_ptr or base_type.is_array:
return base_type.base_type
else:
# TODO: Handle buffers (hopefully without too much redundancy).
return py_object_type
def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1)
......@@ -1612,7 +1776,7 @@ class IndexNode(ExprNode):
self.base.analyse_types(env)
# Handle the case where base is a literal char* (and we expect a string, not an int)
if isinstance(self.base, StringNode):
if isinstance(self.base, BytesNode):
self.base = self.base.coerce_to_pyobject(env)
skip_child_analysis = False
......@@ -2103,6 +2267,9 @@ class SliceNode(ExprNode):
# stop ExprNode
# step ExprNode
type = py_object_type
is_temp = 1
def calculate_constant_result(self):
self.constant_result = self.base.constant_result[
self.start.constant_result : \
......@@ -2133,8 +2300,6 @@ class SliceNode(ExprNode):
self.start = self.start.coerce_to_pyobject(env)
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Constructing Python slice object"
......@@ -2150,13 +2315,14 @@ class SliceNode(ExprNode):
class CallNode(ExprNode):
def analyse_as_type_constructor(self, env):
type = self.function.analyse_as_type(env)
if type and type.is_struct_or_union:
args, kwds = self.explicit_args_kwds()
items = []
for arg, member in zip(args, type.scope.var_entries):
items.append(DictItemNode(pos=arg.pos, key=IdentifierStringNode(pos=arg.pos, value=member.name), value=arg))
items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg))
if kwds:
items += kwds.key_value_pairs
self.key_value_pairs = items
......@@ -2202,6 +2368,20 @@ class SimpleCallNode(CallNode):
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
# TODO: Update when Danilo's C++ code merged in to handle the
# the case of function overloading.
return self.function.type_dependencies(env)
def infer_type(self, env):
func_type = self.function.infer_type(env)
if func_type.is_ptr:
func_type = func_type.base_type
if func_type.is_cfunction:
return func_type.return_type
else:
return py_object_type
def analyse_as_type(self, env):
attr = self.function.as_cython_attribute()
if attr == 'pointer':
......@@ -2462,6 +2642,8 @@ class GeneralCallNode(CallNode):
# keyword_args ExprNode or None Dict of keyword arguments
# starstar_arg ExprNode or None Dict of extra keyword args
type = py_object_type
subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
nogil_check = Node.gil_error
......@@ -2497,7 +2679,7 @@ class GeneralCallNode(CallNode):
self.type = error_type
return error_type
if hasattr(self.function, 'entry') and not self.function.entry.as_variable:
error(self.pos, "Keyword arguments not allowed in cdef functions.")
error(self.pos, "Keyword and starred arguments not allowed in cdef functions.")
else:
self.function = self.function.coerce_to_pyobject(env)
self.positional_args = \
......@@ -2640,6 +2822,18 @@ class AttributeNode(ExprNode):
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
return self.obj.type_dependencies(env)
def infer_type(self, env):
if self.analyse_as_cimported_attribute(env, 0):
return self.entry.type
elif self.analyse_as_unbound_cmethod(env):
return self.entry.type
else:
self.analyse_attribute(env, obj_type = self.obj.infer_type(env))
return self.type
def analyse_target_declaration(self, env):
pass
......@@ -2742,13 +2936,17 @@ class AttributeNode(ExprNode):
self.is_temp = 1
self.result_ctype = py_object_type
def analyse_attribute(self, env):
def analyse_attribute(self, env, obj_type = None):
# Look up attribute and set self.type and self.member.
self.is_py_attr = 0
self.member = self.attribute
if obj_type is None:
if self.obj.type.is_string:
self.obj = self.obj.coerce_to_pyobject(env)
obj_type = self.obj.type
else:
if obj_type.is_string:
obj_type = py_object_type
if obj_type.is_ptr or obj_type.is_array:
obj_type = obj_type.base_type
self.op = "->"
......@@ -2787,9 +2985,10 @@ class AttributeNode(ExprNode):
# type, or it is an extension type and the attribute is either not
# declared or is declared as a Python method. Treat it as a Python
# attribute reference.
self.analyse_as_python_attribute(env)
self.analyse_as_python_attribute(env, obj_type)
def analyse_as_python_attribute(self, env):
def analyse_as_python_attribute(self, env, obj_type = None):
if obj_type is None:
obj_type = self.obj.type
self.member = self.attribute
if obj_type.is_pyobject:
......@@ -2840,7 +3039,7 @@ class AttributeNode(ExprNode):
else:
return self.member
elif obj.type.is_complex:
return "__Pyx_%s_PART(%s)" % (self.member.upper(), obj_code)
return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
else:
return "%s%s%s" % (obj_code, self.op, self.member)
......@@ -2943,6 +3142,7 @@ class StarredTargetNode(ExprNode):
subexprs = ['target']
is_starred = 1
type = py_object_type
is_temp = 1
def __init__(self, pos, target):
self.pos = pos
......@@ -3204,6 +3404,8 @@ class SequenceNode(ExprNode):
class TupleNode(SequenceNode):
# Tuple constructor.
type = tuple_type
gil_message = "Constructing Python tuple"
def analyse_types(self, env, skip_children=False):
......@@ -3212,7 +3414,6 @@ class TupleNode(SequenceNode):
self.is_literal = 1
else:
SequenceNode.analyse_types(self, env, skip_children)
self.type = tuple_type
def calculate_result_code(self):
if len(self.args) > 0:
......@@ -3272,6 +3473,13 @@ class ListNode(SequenceNode):
gil_message = "Constructing Python list"
def type_dependencies(self, env):
return ()
def infer_type(self, env):
# TOOD: Infer non-object list arrays.
return list_type
def analyse_expressions(self, env):
SequenceNode.analyse_expressions(self, env)
self.coerce_to_pyobject(env)
......@@ -3378,10 +3586,16 @@ class ComprehensionNode(ExprNode):
subexprs = ["target"]
child_attrs = ["loop", "append"]
def infer_type(self, env):
return self.target.infer_type(env)
def analyse_types(self, env):
self.target.analyse_expressions(env)
self.type = self.target.type
self.append.target = self # this is a CloneNode used in the PyList_Append in the inner loop
# We are analysing declarations to late.
self.loop.target.analyse_target_declaration(env)
env.infer_types()
self.loop.analyse_declarations(env)
self.loop.analyse_expressions(env)
......@@ -3451,6 +3665,8 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
class SetNode(ExprNode):
# Set constructor.
type = set_type
subexprs = ['args']
gil_message = "Constructing Python set"
......@@ -3518,6 +3734,13 @@ class DictNode(ExprNode):
except Exception, e:
self.compile_time_value_error(e)
def type_dependencies(self, env):
return ()
def infer_type(self, env):
# TOOD: Infer struct constructors.
return dict_type
def analyse_types(self, env):
hold_errors()
for item in self.key_value_pairs:
......@@ -3539,9 +3762,9 @@ class DictNode(ExprNode):
for item in self.key_value_pairs:
if isinstance(item.key, CoerceToPyTypeNode):
item.key = item.key.arg
if not isinstance(item.key, (StringNode, IdentifierStringNode)):
if not isinstance(item.key, (UnicodeNode, StringNode, BytesNode)):
error(item.key.pos, "Invalid struct field identifier")
item.key = IdentifierStringNode(item.key.pos, value="<error>")
item.key = StringNode(item.key.pos, value="<error>")
else:
key = str(item.key.value) # converts string literals to unicode in Py3
member = dst_type.scope.lookup_here(key)
......@@ -3707,12 +3930,13 @@ class UnboundMethodNode(ExprNode):
#
# function ExprNode Function object
type = py_object_type
is_temp = 1
subexprs = ['function']
def analyse_types(self, env):
self.function.analyse_types(env)
self.type = py_object_type
self.is_temp = 1
gil_message = "Constructing an unbound method"
......@@ -3737,9 +3961,11 @@ class PyCFunctionNode(ExprNode):
subexprs = []
self_object = None
type = py_object_type
is_temp = 1
def analyse_types(self, env):
self.type = py_object_type
self.is_temp = 1
pass
gil_message = "Constructing Python function"
......@@ -3830,6 +4056,9 @@ class UnopNode(ExprNode):
except Exception, e:
self.compile_time_value_error(e)
def infer_type(self, env):
return self.operand.infer_type(env)
def analyse_types(self, env):
self.operand.analyse_types(env)
if self.is_py_operation():
......@@ -3878,6 +4107,10 @@ class NotNode(ExprNode):
#
# operand ExprNode
type = PyrexTypes.c_bint_type
subexprs = ['operand']
def calculate_constant_result(self):
self.constant_result = not self.operand.constant_result
......@@ -3888,12 +4121,12 @@ class NotNode(ExprNode):
except Exception, e:
self.compile_time_value_error(e)
subexprs = ['operand']
def infer_type(self, env):
return PyrexTypes.c_bint_type
def analyse_types(self, env):
self.operand.analyse_types(env)
self.operand = self.operand.coerce_to_boolean(env)
self.type = PyrexTypes.c_bint_type
def calculate_result_code(self):
return "(!%s)" % self.operand.result()
......@@ -3928,7 +4161,7 @@ class UnaryMinusNode(UnopNode):
else:
self.type_error()
if self.type.is_complex:
self.infix = env.directives['c99_complex']
self.infix = False
def py_operation_function(self):
return "PyNumber_Negative"
......@@ -3962,6 +4195,9 @@ class AmpersandNode(ExprNode):
subexprs = ['operand']
def infer_type(self, env):
return PyrexTypes.c_ptr_type(self.operand.infer_type(env))
def analyse_types(self, env):
self.operand.analyse_types(env)
argtype = self.operand.type
......@@ -4019,6 +4255,15 @@ class TypecastNode(ExprNode):
subexprs = ['operand']
base_type = declarator = type = None
def type_dependencies(self, env):
return ()
def infer_type(self, env):
if self.type is None:
base_type = self.base_type.analyse(env)
_, self.type = self.declarator.analyse(base_type, env)
return self.type
def analyse_types(self, env):
if self.type is None:
base_type = self.base_type.analyse(env)
......@@ -4037,14 +4282,19 @@ class TypecastNode(ExprNode):
self.result_ctype = py_object_type
self.operand = self.operand.coerce_to_pyobject(env)
else:
if not (self.operand.type.is_ptr and self.operand.type.base_type.is_void):
if self.operand.type.is_ptr:
if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct):
error(self.pos, "Python objects cannot be cast from pointers of primitive types")
else:
# Should this be an error?
warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
self.operand = self.operand.coerce_to_simple(env)
elif from_py and not to_py:
if self.type.create_from_py_utility_code(env):
self.operand = self.operand.coerce_to(self.type, env)
elif self.type.is_ptr and not (self.type.base_type.is_void or self.type.base_type.is_struct):
error(self.pos, "Python objects cannot be casted to pointers of primitive types")
elif self.type.is_ptr:
if not (self.type.base_type.is_void or self.type.base_type.is_struct):
error(self.pos, "Python objects cannot be cast to pointers of primitive types")
else:
warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.type, self.operand.type))
elif from_py and to_py:
......@@ -4168,6 +4418,29 @@ class SizeofVarNode(SizeofNode):
def generate_result_code(self, code):
pass
class TypeofNode(ExprNode):
# Compile-time type of an expression, as a string.
#
# operand ExprNode
# literal StringNode # internal
literal = None
type = py_object_type
subexprs = ['operand', 'literal']
def analyse_types(self, env):
self.operand.analyse_types(env)
self.literal = StringNode(
self.pos, value=StringEncoding.EncodedString(str(self.operand.type)))
self.literal.analyse_types(env)
self.literal = self.literal.coerce_to_pyobject(env)
def generate_evaluation_code(self, code):
self.literal.generate_evaluation_code(code)
def calculate_result_code(self):
return self.literal.calculate_result_code()
#-------------------------------------------------------------------
#
......@@ -4241,6 +4514,10 @@ class BinopNode(ExprNode):
except Exception, e:
self.compile_time_value_error(e)
def infer_type(self, env):
return self.result_type(self.operand1.infer_type(env),
self.operand2.infer_type(env))
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
......@@ -4254,8 +4531,16 @@ class BinopNode(ExprNode):
self.analyse_c_operation(env)
def is_py_operation(self):
return (self.operand1.type.is_pyobject
or self.operand2.type.is_pyobject)
return self.is_py_operation_types(self.operand1.type, self.operand2.type)
def is_py_operation_types(self, type1, type2):
return type1.is_pyobject or type2.is_pyobject
def result_type(self, type1, type2):
if self.is_py_operation_types(type1, type2):
return py_object_type
else:
return self.compute_c_result_type(type1, type2)
def nogil_check(self, env):
if self.is_py_operation():
......@@ -4308,7 +4593,7 @@ class NumBinopNode(BinopNode):
if not self.type:
self.type_error()
return
if self.type.is_complex and not env.directives['c99_complex']:
if self.type.is_complex:
self.infix = False
if not self.infix:
self.operand1 = self.operand1.coerce_to(self.type, env)
......@@ -4379,12 +4664,11 @@ class IntBinopNode(NumBinopNode):
class AddNode(NumBinopNode):
# '+' operator.
def is_py_operation(self):
if self.operand1.type.is_string \
and self.operand2.type.is_string:
def is_py_operation_types(self, type1, type2):
if type1.is_string and type2.is_string:
return 1
else:
return NumBinopNode.is_py_operation(self)
return NumBinopNode.is_py_operation_types(self, type1, type2)
def compute_c_result_type(self, type1, type2):
#print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
......@@ -4413,14 +4697,12 @@ class SubNode(NumBinopNode):
class MulNode(NumBinopNode):
# '*' operator.
def is_py_operation(self):
type1 = self.operand1.type
type2 = self.operand2.type
def is_py_operation_types(self, type1, type2):
if (type1.is_string and type2.is_int) \
or (type2.is_string and type1.is_int):
return 1
else:
return NumBinopNode.is_py_operation(self)
return NumBinopNode.is_py_operation_types(self, type1, type2)
class DivNode(NumBinopNode):
......@@ -4557,10 +4839,10 @@ class DivNode(NumBinopNode):
class ModNode(DivNode):
# '%' operator.
def is_py_operation(self):
return (self.operand1.type.is_string
or self.operand2.type.is_string
or NumBinopNode.is_py_operation(self))
def is_py_operation_types(self, type1, type2):
return (type1.is_string
or type2.is_string
or NumBinopNode.is_py_operation_types(self, type1, type2))
def zero_division_message(self):
if self.type.is_int:
......@@ -4637,6 +4919,11 @@ class BoolBinopNode(ExprNode):
subexprs = ['operand1', 'operand2']
def infer_type(self, env):
type1 = self.operand1.infer_type(env)
type2 = self.operand2.infer_type(env)
return PyrexTypes.spanning_type(type1, type2)
def calculate_constant_result(self):
if self.operator == 'and':
self.constant_result = \
......@@ -4664,22 +4951,14 @@ class BoolBinopNode(ExprNode):
def analyse_types(self, env):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
if self.operand1.type.is_pyobject or \
self.operand2.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_pyobject(env)
self.operand2 = self.operand2.coerce_to_pyobject(env)
self.type = py_object_type
else:
self.operand1 = self.operand1.coerce_to_boolean(env)
self.operand2 = self.operand2.coerce_to_boolean(env)
self.type = PyrexTypes.c_bint_type
# Below disabled for
self.type = PyrexTypes.spanning_type(self.operand1.type, self.operand2.type)
self.operand1 = self.operand1.coerce_to(self.type, env)
self.operand2 = self.operand2.coerce_to(self.type, env)
# For what we're about to do, it's vital that
# both operands be temp nodes.
# self.operand1 = self.operand1.coerce_to_temp(env) #CTT
# self.operand2 = self.operand2.coerce_to_temp(env)
self.operand1 = self.operand1.coerce_to_simple(env)
self.operand2 = self.operand2.coerce_to_simple(env)
self.is_temp = 1
gil_message = "Truth-testing Python object"
......@@ -4688,14 +4967,6 @@ class BoolBinopNode(ExprNode):
self.operand1.check_const()
self.operand2.check_const()
def calculate_result_code(self):
return "(%s %s %s)" % (
self.operand1.result(),
self.py_to_c_op[self.operator],
self.operand2.result())
py_to_c_op = {'and': "&&", 'or': "||"}
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
self.operand1.generate_evaluation_code(code)
......@@ -4751,6 +5022,13 @@ class CondExprNode(ExprNode):
subexprs = ['test', 'true_val', 'false_val']
def type_dependencies(self, env):
return self.true_val.type_dependencies(env) + self.false_val.type_dependencies(env)
def infer_type(self, env):
return self.compute_result_type(self.true_val.infer_type(env),
self.false_val.infer_type(env))
def calculate_constant_result(self):
if self.test.constant_result:
self.constant_result = self.true_val.constant_result
......@@ -4835,6 +5113,10 @@ class CmpNode(object):
# Mixin class containing code common to PrimaryCmpNodes
# and CascadedCmpNodes.
def infer_types(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def calculate_cascaded_constant_result(self, operand1_result):
func = compile_time_binary_operators[self.operator]
operand2_result = self.operand2.constant_result
......@@ -4859,45 +5141,124 @@ class CmpNode(object):
result = result and cascade.compile_time_value(operand2, denv)
return result
def find_common_int_type(self, env, op, operand1, operand2):
# type1 != type2 and at least one of the types is not a C int
type1 = operand1.type
type2 = operand2.type
type1_can_be_int = False
type2_can_be_int = False
if isinstance(operand1, (StringNode, BytesNode)) \
and operand1.can_coerce_to_char_literal():
type1_can_be_int = True
if isinstance(operand2, (StringNode, BytesNode)) \
and operand2.can_coerce_to_char_literal():
type2_can_be_int = True
if type1.is_int:
if type2_can_be_int:
return type1
elif type2.is_int:
if type1_can_be_int:
return type2
elif type1_can_be_int:
if type2_can_be_int:
return PyrexTypes.c_uchar_type
return None
def find_common_type(self, env, op, operand1, common_type=None):
operand2 = self.operand2
type1 = operand1.type
type2 = operand2.type
new_common_type = None
# catch general errors
if type1 == str_type and (type2.is_string or type2 in (bytes_type, unicode_type)) or \
type2 == str_type and (type1.is_string or type1 in (bytes_type, unicode_type)):
error(self.pos, "Comparisons between bytes/unicode and str are not portable to Python 3")
new_common_type = error_type
# try to use numeric comparisons where possible
elif type1.is_complex or type2.is_complex:
if op not in ('==', '!='):
error(self.pos, "complex types are unordered")
new_common_type = error_type
if type1.is_pyobject:
new_common_type = type1
elif type2.is_pyobject:
new_common_type = type2
else:
new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
elif type1.is_numeric and type2.is_numeric:
new_common_type = PyrexTypes.widest_numeric_type(type1, type2)
elif common_type is None or not common_type.is_pyobject:
new_common_type = self.find_common_int_type(env, op, operand1, operand2)
if new_common_type is None:
# fall back to generic type compatibility tests
if type1 == type2 or type1.assignable_from(type2):
new_common_type = type1
elif type2.assignable_from(type1):
new_common_type = type2
elif type1.is_pyobject and type2.is_pyobject:
new_common_type = py_object_type
elif type1.is_pyobject or type2.is_pyobject:
if type2.is_numeric or type2.is_string:
if operand2.check_for_coercion_error(type1):
new_common_type = error_type
else:
new_common_type = type1
elif type1.is_numeric or type1.is_string:
if operand1.check_for_coercion_error(type2):
new_common_type = error_type
else:
new_common_type = type2
else:
# one Python type and one non-Python type, not assignable
self.invalid_types_error(operand1, op, operand2)
new_common_type = error_type
else:
# C types that we couldn't handle up to here are an error
self.invalid_types_error(operand1, op, operand2)
new_common_type = error_type
# recursively merge types
if common_type is None or new_common_type.is_error:
common_type = new_common_type
else:
# we could do a lot better by splitting the comparison
# into a non-Python part and a Python part, but this is
# safer for now
common_type = PyrexTypes.spanning_type(common_type, new_common_type)
if self.cascade:
common_type = self.cascade.find_common_type(env, self.operator, operand2, common_type)
return common_type
def invalid_types_error(self, operand1, op, operand2):
error(self.pos, "Invalid types for '%s' (%s, %s)" %
(op, operand1.type, operand2.type))
def is_python_comparison(self):
return (self.has_python_operands()
or (self.cascade and self.cascade.is_python_comparison())
or self.operator in ('in', 'not_in'))
def coerce_operands_to(self, dst_type, env):
operand2 = self.operand2
if operand2.type != dst_type:
self.operand2 = operand2.coerce_to(dst_type, env)
if self.cascade:
self.cascade.coerce_operands_to(dst_type, env)
def is_python_result(self):
return ((self.has_python_operands() and self.operator not in ('is', 'is_not', 'in', 'not_in'))
return ((self.has_python_operands() and
self.operator not in ('is', 'is_not', 'in', 'not_in'))
or (self.cascade and self.cascade.is_python_result()))
def check_types(self, env, operand1, op, operand2):
if operand1.type.is_complex or operand2.type.is_complex:
if op not in ('==', '!='):
error(self.pos, "complex types unordered")
common_type = PyrexTypes.widest_numeric_type(operand1.type, operand2.type)
self.operand1 = operand1.coerce_to(common_type, env)
self.operand2 = operand2.coerce_to(common_type, env)
elif not self.types_okay(operand1, op, operand2):
error(self.pos, "Invalid types for '%s' (%s, %s)" %
(self.operator, operand1.type, operand2.type))
def types_okay(self, operand1, op, operand2):
type1 = operand1.type
type2 = operand2.type
if type1.is_error or type2.is_error:
return 1
if type1.is_pyobject: # type2 will be, too
return 1
elif type1.is_ptr or type1.is_array:
return type1.is_null_ptr or type2.is_null_ptr \
or ((type2.is_ptr or type2.is_array)
and type1.base_type.same_as(type2.base_type))
elif ((type1.is_numeric and type2.is_numeric
or type1.is_enum and (type1 is type2 or type2.is_int)
or type1.is_int and type2.is_enum)
and op not in ('is', 'is_not')):
return 1
else:
return type1.is_cfunction and type1.is_cfunction and type1 == type2
def generate_operation_code(self, code, result_code,
operand1, op , operand2):
if self.type is PyrexTypes.py_object_type:
......@@ -4941,9 +5302,11 @@ class CmpNode(object):
richcmp_constants[op],
code.error_goto_if_null(result_code, self.pos)))
code.put_gotref(result_code)
elif operand1.type.is_complex and not code.globalstate.directives['c99_complex']:
if op == "!=": negation = "!"
else: negation = ""
elif operand1.type.is_complex:
if op == "!=":
negation = "!"
else:
negation = ""
code.putln("%s = %s(%s%s(%s, %s));" % (
result_code,
coerce_result,
......@@ -4997,6 +5360,13 @@ class PrimaryCmpNode(ExprNode, CmpNode):
cascade = None
def infer_type(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def type_dependencies(self, env):
return ()
def calculate_constant_result(self):
self.constant_result = self.calculate_cascaded_constant_result(
self.operand1.constant_result)
......@@ -5009,16 +5379,23 @@ class PrimaryCmpNode(ExprNode, CmpNode):
self.operand1.analyse_types(env)
self.operand2.analyse_types(env)
if self.cascade:
self.cascade.analyse_types(env, self.operand2)
self.is_pycmp = self.is_python_comparison()
if self.is_pycmp:
self.coerce_operands_to_pyobjects(env)
if self.has_int_operands():
self.coerce_chars_to_ints(env)
self.cascade.analyse_types(env)
if self.operator in ('in', 'not_in'):
common_type = py_object_type
self.is_pycmp = True
else:
common_type = self.find_common_type(env, self.operator, self.operand1)
self.is_pycmp = common_type.is_pyobject
if not common_type.is_error:
if self.operand1.type != common_type:
self.operand1 = self.operand1.coerce_to(common_type, env)
self.coerce_operands_to(common_type, env)
if self.cascade:
self.operand2 = self.operand2.coerce_to_simple(env)
self.cascade.coerce_cascaded_operands_to_temp(env)
self.check_operand_types(env)
if self.is_python_result():
self.type = PyrexTypes.py_object_type
else:
......@@ -5030,35 +5407,10 @@ class PrimaryCmpNode(ExprNode, CmpNode):
if self.is_pycmp or self.cascade:
self.is_temp = 1
def check_operand_types(self, env):
self.check_types(env,
self.operand1, self.operator, self.operand2)
if self.cascade:
self.cascade.check_operand_types(env, self.operand2)
def has_python_operands(self):
return (self.operand1.type.is_pyobject
or self.operand2.type.is_pyobject)
def coerce_operands_to_pyobjects(self, env):
self.operand1 = self.operand1.coerce_to_pyobject(env)
self.operand2 = self.operand2.coerce_to_pyobject(env)
if self.cascade:
self.cascade.coerce_operands_to_pyobjects(env)
def has_int_operands(self):
return (self.operand1.type.is_int or self.operand2.type.is_int) \
or (self.cascade and self.cascade.has_int_operands())
def coerce_chars_to_ints(self, env):
# coerce literal single-char strings to c chars
if self.operand1.type.is_string and isinstance(self.operand1, StringNode):
self.operand1 = self.operand1.coerce_to(PyrexTypes.c_uchar_type, env)
if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
if self.cascade:
self.cascade.coerce_chars_to_ints(env)
def check_const(self):
self.operand1.check_const()
self.operand2.check_const()
......@@ -5131,16 +5483,17 @@ class CascadedCmpNode(Node, CmpNode):
cascade = None
constant_result = constant_value_not_set # FIXME: where to calculate this?
def analyse_types(self, env, operand1):
self.operand2.analyse_types(env)
if self.cascade:
self.cascade.analyse_types(env, self.operand2)
def infer_type(self, env):
# TODO: Actually implement this (after merging with -unstable).
return py_object_type
def check_operand_types(self, env, operand1):
self.check_types(env,
operand1, self.operator, self.operand2)
def type_dependencies(self, env):
return ()
def analyse_types(self, env):
self.operand2.analyse_types(env)
if self.cascade:
self.cascade.check_operand_types(env, self.operand2)
self.cascade.analyse_types(env)
def has_python_operands(self):
return self.operand2.type.is_pyobject
......@@ -5150,13 +5503,6 @@ class CascadedCmpNode(Node, CmpNode):
if self.cascade:
self.cascade.coerce_operands_to_pyobjects(env)
def has_int_operands(self):
return self.operand2.type.is_int
def coerce_chars_to_ints(self, env):
if self.operand2.type.is_string and isinstance(self.operand2, StringNode):
self.operand2 = self.operand2.coerce_to(PyrexTypes.c_uchar_type, env)
def coerce_cascaded_operands_to_temp(self, env):
if self.cascade:
#self.operand2 = self.operand2.coerce_to_temp(env) #CTT
......@@ -5353,10 +5699,11 @@ class CoerceToPyTypeNode(CoercionNode):
# This node is used to convert a C data type
# to a Python object.
type = py_object_type
is_temp = 1
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
self.type = py_object_type
self.is_temp = 1
if not arg.type.create_to_py_utility_code(env):
error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type)
......@@ -5424,9 +5771,10 @@ class CoerceToBooleanNode(CoercionNode):
# This node is used when a result needs to be used
# in a boolean context.
type = PyrexTypes.c_bint_type
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
self.type = PyrexTypes.c_bint_type
if arg.type.is_pyobject:
self.is_temp = 1
......@@ -5463,8 +5811,8 @@ class CoerceToComplexNode(CoercionNode):
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()
real_part = "__Pyx_CREAL(%s)" % self.arg.result()
imag_part = "__Pyx_CIMAG(%s)" % self.arg.result()
else:
real_part = self.arg.result()
imag_part = "0"
......@@ -5505,7 +5853,7 @@ class CoerceToTempNode(CoercionNode):
# by generic generate_subexpr_evaluation_code!
code.putln("%s = %s;" % (
self.result(), self.arg.result_as(self.ctype())))
if self.type.is_pyobject:
if self.type.is_pyobject and self.use_managed_ref:
code.put_incref(self.result(), self.ctype())
......@@ -5531,6 +5879,12 @@ class CloneNode(CoercionNode):
def result(self):
return self.arg.result()
def type_dependencies(self, env):
return self.arg.type_dependencies(env)
def infer_type(self, env):
return self.arg.infer_type(env)
def analyse_types(self, env):
self.type = self.arg.type
self.result_ctype = self.arg.result_ctype
......
......@@ -87,6 +87,7 @@ class Context(object):
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from TypeInference import MarkAssignments
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature
......@@ -131,6 +132,7 @@ class Context(object):
CreateClosureClasses(self),
AutoTestDictTransform(self),
EmbedSignature(self),
MarkAssignments(self),
TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self),
_check_c_declarations,
......
......@@ -260,11 +260,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
globalstate.module_pos = self.pos
globalstate.directives = self.directives
globalstate.use_utility_code(refcount_utility_code)
globalstate.use_utility_code(refnanny_utility_code)
code = globalstate['before_global_var']
code.putln('#define __Pyx_MODULE_NAME "%s"' % self.full_module_name)
code.putln("int %s%s = %s;" % (Naming.module_is_main, self.full_module_name.replace('.', '__'), int(Options.embed)))
code.putln("int %s%s = 0;" % (Naming.module_is_main, self.full_module_name.replace('.', '__')))
code.putln("")
code.putln("/* Implementation of %s */" % env.qualified_name)
......@@ -437,6 +437,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#if PY_VERSION_HEX < 0x02040000")
code.putln(" #define METH_COEXIST 0")
code.putln(" #define PyDict_CheckExact(op) (Py_TYPE(op) == &PyDict_Type)")
code.putln(" #define PyDict_Contains(d,o) PySequence_Contains(d,o)")
code.putln("#endif")
code.putln("#if PY_VERSION_HEX < 0x02050000")
......@@ -457,6 +458,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(" #define PyVarObject_HEAD_INIT(type, size) \\")
code.putln(" PyObject_HEAD_INIT(type) size,")
code.putln(" #define PyType_Modified(t)")
code.putln(" #define PyBytes_CheckExact PyString_CheckExact")
code.putln("")
code.putln(" typedef struct {")
code.putln(" void *buf;")
......@@ -497,8 +499,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#if PY_MAJOR_VERSION >= 3")
code.putln(" #define PyBaseString_Type PyUnicode_Type")
code.putln(" #define PyString_Type PyBytes_Type")
code.putln(" #define PyString_CheckExact PyBytes_CheckExact")
code.putln(" #define PyString_Type PyUnicode_Type")
code.putln(" #define PyString_CheckExact PyUnicode_CheckExact")
code.putln(" #define PyInt_Type PyLong_Type")
code.putln(" #define PyInt_Check(op) PyLong_Check(op)")
code.putln(" #define PyInt_CheckExact(op) PyLong_CheckExact(op)")
......@@ -561,12 +563,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
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>")
if env.directives['ccomplex']:
code.putln("")
code.putln("#if !defined(CYTHON_CCOMPLEX)")
code.putln("#define CYTHON_CCOMPLEX 1")
code.putln("#endif")
code.putln("#define __PYX_USE_C99_COMPLEX defined(_Complex_I)")
code.putln('')
code.putln("")
code.put(Nodes.utility_function_predeclarations)
code.put(PyrexTypes.type_conversion_predeclarations)
code.put(Nodes.branch_prediction_macros)
......@@ -1637,19 +1639,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("{")
tempdecl_code = code.insertion_point()
self.generate_filename_init_call(code)
code.putln("#ifdef CYTHON_REFNANNY")
code.putln("void* __pyx_refchk = NULL;")
code.putln("__Pyx_Refnanny = __Pyx_ImportRefcountAPI(\"refnanny\");")
code.putln("if (!__Pyx_Refnanny) {")
code.putln("#if CYTHON_REFNANNY")
code.putln("void* __pyx_refnanny = NULL;")
code.putln("__Pyx_RefNanny = __Pyx_RefNannyImportAPI(\"refnanny\");")
code.putln("if (!__Pyx_RefNanny) {")
code.putln(" PyErr_Clear();")
code.putln(" __Pyx_Refnanny = __Pyx_ImportRefcountAPI(\"Cython.Runtime.refnanny\");")
code.putln(" if (!__Pyx_Refnanny)")
code.putln(" Py_FatalError(\"failed to import refnanny module\");")
code.putln(" __Pyx_RefNanny = __Pyx_RefNannyImportAPI(\"Cython.Runtime.refnanny\");")
code.putln(" if (!__Pyx_RefNanny)")
code.putln(" Py_FatalError(\"failed to import 'refnanny' module\");")
code.putln("}")
code.putln("__pyx_refchk = __Pyx_Refnanny->NewContext(\"%s\", __LINE__, __FILE__);"% header3)
code.putln("__pyx_refnanny = __Pyx_RefNanny->SetupContext(\"%s\", __LINE__, __FILE__);"% header3)
code.putln("#endif")
self.generate_filename_init_call(code)
code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)));
code.putln("#if PY_MAJOR_VERSION < 3");
code.putln("%s = PyString_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos)));
......@@ -1784,10 +1787,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# code.putln("Py_DECREF(%s); %s = 0;" % (
# code.entry_as_pyobject(entry), entry.cname))
code.putln("Py_INCREF(Py_None); return Py_None;")
code.putln('}')
def generate_main_method(self, env, code):
code.globalstate.use_utility_code(main_method.specialize(module_name=env.module_name))
module_is_main = "%s%s" % (Naming.module_is_main, self.full_module_name.replace('.', '__'))
code.globalstate.use_utility_code(main_method.specialize(module_name=env.module_name, module_is_main=module_is_main))
def generate_filename_init_call(self, code):
code.putln("%s();" % Naming.fileinit_cname)
......@@ -2200,11 +2203,6 @@ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *s
""",
impl = r"""
static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig) {
#if PY_VERSION_HEX < 0x02050000
char *api = (char *)"%(API)s";
#else
const char *api = "%(API)s";
#endif
PyObject *d = 0;
PyObject *cobj = 0;
union {
......@@ -2212,19 +2210,22 @@ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *s
void *p;
} tmp;
d = PyObject_GetAttrString(%(MODULE)s, api);
d = PyObject_GetAttrString(%(MODULE)s, (char *)"%(API)s");
if (!d) {
PyErr_Clear();
d = PyDict_New();
if (!d)
goto bad;
Py_INCREF(d);
if (PyModule_AddObject(%(MODULE)s, api, d) < 0)
if (PyModule_AddObject(%(MODULE)s, (char *)"%(API)s", d) < 0)
goto bad;
}
tmp.fp = f;
#if PY_VERSION_HEX < 0x03010000
cobj = PyCObject_FromVoidPtrAndDesc(tmp.p, (void *)sig, 0);
#else
cobj = PyCapsule_New(tmp.p, sig, 0);
#endif
if (!cobj)
goto bad;
if (PyDict_SetItemString(d, name, cobj) < 0)
......@@ -2240,8 +2241,6 @@ bad:
""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
)
#------------------------------------------------------------------------------------
function_import_utility_code = UtilityCode(
proto = """
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/
......@@ -2250,21 +2249,17 @@ impl = """
#ifndef __PYX_HAVE_RT_ImportFunction
#define __PYX_HAVE_RT_ImportFunction
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig) {
#if PY_VERSION_HEX < 0x02050000
char *api = (char *)"%(API)s";
#else
const char *api = "%(API)s";
#endif
PyObject *d = 0;
PyObject *cobj = 0;
const char *desc;
const char *s1, *s2;
union {
void (*fp)(void);
void *p;
} tmp;
#if PY_VERSION_HEX < 0x03010000
const char *desc, *s1, *s2;
#endif
d = PyObject_GetAttrString(module, api);
d = PyObject_GetAttrString(module, (char *)"%(API)s");
if (!d)
goto bad;
cobj = PyDict_GetItemString(d, funcname);
......@@ -2274,6 +2269,7 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
PyModule_GetName(module), funcname);
goto bad;
}
#if PY_VERSION_HEX < 0x03010000
desc = (const char *)PyCObject_GetDesc(cobj);
if (!desc)
goto bad;
......@@ -2286,7 +2282,18 @@ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**
goto bad;
}
tmp.p = PyCObject_AsVoidPtr(cobj);
#else
if (!PyCapsule_IsValid(cobj, sig)) {
PyErr_Format(PyExc_TypeError,
"C function %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj));
goto bad;
}
tmp.p = PyCapsule_GetPointer(cobj, sig);
#endif
*f = tmp.fp;
if (!(*f))
goto bad;
Py_DECREF(d);
return 0;
bad:
......@@ -2297,6 +2304,8 @@ bad:
""" % dict(API = Naming.api_name)
)
#------------------------------------------------------------------------------------
register_cleanup_utility_code = UtilityCode(
proto = """
static int __Pyx_RegisterCleanup(void); /*proto*/
......@@ -2447,39 +2456,54 @@ bad:
""" % {'IMPORT_STAR' : Naming.import_star,
'IMPORT_STAR_SET' : Naming.import_star_set }
refcount_utility_code = UtilityCode(proto="""
#ifdef CYTHON_REFNANNY
typedef struct {
refnanny_utility_code = UtilityCode(proto="""
#ifndef CYTHON_REFNANNY
#define CYTHON_REFNANNY 0
#endif
#if CYTHON_REFNANNY
typedef struct {
void (*INCREF)(void*, PyObject*, int);
void (*DECREF)(void*, PyObject*, int);
void (*GOTREF)(void*, PyObject*, int);
void (*GIVEREF)(void*, PyObject*, int);
void* (*NewContext)(const char*, int, const char*);
void* (*SetupContext)(const char*, int, const char*);
void (*FinishContext)(void**);
} __Pyx_RefnannyAPIStruct;
static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL;
#define __Pyx_ImportRefcountAPI(name) \
(__Pyx_RefnannyAPIStruct *) PyCObject_Import((char *)name, (char *)\"RefnannyAPI\")
#define __Pyx_INCREF(r) __Pyx_Refnanny->INCREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_DECREF(r) __Pyx_Refnanny->DECREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_GOTREF(r) __Pyx_Refnanny->GOTREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_Refnanny->GIVEREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_XDECREF(r) if((r) == NULL) ; else __Pyx_DECREF(r)
#define __Pyx_SetupRefcountContext(name) \
void* __pyx_refchk = __Pyx_Refnanny->NewContext((name), __LINE__, __FILE__)
#define __Pyx_FinishRefcountContext() \
__Pyx_Refnanny->FinishContext(&__pyx_refchk)
} __Pyx_RefNannyAPIStruct;
static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) {
PyObject *m = NULL, *p = NULL;
void *r = NULL;
m = PyImport_ImportModule((char *)modname);
if (!m) goto end;
p = PyObject_GetAttrString(m, (char *)\"RefNannyAPI\");
if (!p) goto end;
r = PyLong_AsVoidPtr(p);
end:
Py_XDECREF(p);
Py_XDECREF(m);
return (__Pyx_RefNannyAPIStruct *)r;
}
#define __Pyx_RefNannySetupContext(name) \
void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
#define __Pyx_RefNannyFinishContext() \
__Pyx_RefNanny->FinishContext(&__pyx_refnanny)
#define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0)
#else
#define __Pyx_INCREF(r) Py_INCREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_GOTREF(r)
#define __Pyx_GIVEREF(r)
#define __Pyx_XDECREF(r) Py_XDECREF(r)
#define __Pyx_SetupRefcountContext(name)
#define __Pyx_FinishRefcountContext()
#define __Pyx_RefNannySetupContext(name)
#define __Pyx_RefNannyFinishContext()
#define __Pyx_INCREF(r) Py_INCREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_GOTREF(r)
#define __Pyx_GIVEREF(r)
#define __Pyx_XDECREF(r) Py_XDECREF(r)
#endif /* CYTHON_REFNANNY */
#define __Pyx_XGIVEREF(r) if((r) == NULL) ; else __Pyx_GIVEREF(r)
#define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r)
#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0)
#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0)
""")
......@@ -2495,6 +2519,7 @@ int wmain(int argc, wchar_t **argv) {
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
%(module_is_main)s = 1;
#if PY_MAJOR_VERSION < 3
init%(module_name)s();
#else
......
......@@ -4,6 +4,12 @@
import sys, os, time, copy
try:
set
except NameError:
# Python 2.3
from sets import Set as set
import Code
import Builtin
from Errors import error, warning, InternalError
......@@ -11,7 +17,7 @@ import Naming
import PyrexTypes
import TypeSlots
from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
from Symtab import ModuleScope, LocalScope, ClosureScope, \
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, ClosureScope, \
StructOrUnionScope, PyClassScope, CClassScope
from Cython.Utils import open_new_file, replace_suffix
from Code import UtilityCode
......@@ -2525,7 +2531,7 @@ class OverrideCheckNode(StatNode):
else:
first_arg = 1
import ExprNodes
self.func_node = ExprNodes.PyTempNode(self.pos, env)
self.func_node = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
call_tuple = ExprNodes.TupleNode(self.pos, args=[ExprNodes.NameNode(self.pos, name=arg.name) for arg in self.args[first_arg:]])
call_node = ExprNodes.SimpleCallNode(self.pos,
function=self.func_node,
......@@ -2547,21 +2553,22 @@ class OverrideCheckNode(StatNode):
code.putln("else {")
else:
code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
self.func_node.allocate(code)
err = code.error_goto_if_null(self.func_node.result(), self.pos)
func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
self.func_node.set_cname(func_node_temp)
# need to get attribute manually--scope would return cdef method
err = code.error_goto_if_null(func_node_temp, self.pos)
code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
self.func_node.result(), self_arg, interned_attr_cname, err))
code.put_gotref(self.func_node.py_result())
is_builtin_function_or_method = 'PyCFunction_Check(%s)' % self.func_node.result()
is_overridden = '(PyCFunction_GET_FUNCTION(%s) != (void *)&%s)' % (
self.func_node.result(), self.py_func.entry.func_cname)
code.putln('if (!%s || %s) {' % (is_builtin_function_or_method, is_overridden))
func_node_temp, self_arg, interned_attr_cname, err))
code.put_gotref(func_node_temp)
is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
is_overridden = "(PyCFunction_GET_FUNCTION(%s) != (void *)&%s)" % (
func_node_temp, self.py_func.entry.func_cname)
code.putln("if (!%s || %s) {" % (is_builtin_function_or_method, is_overridden))
self.body.generate_execution_code(code)
code.putln('}')
code.put_decref_clear(self.func_node.result(), PyrexTypes.py_object_type)
code.putln("}")
self.func_node.release(code)
code.put_decref_clear(func_node_temp, PyrexTypes.py_object_type)
code.funcstate.release_temp(func_node_temp)
code.putln("}")
class ClassDefNode(StatNode, BlockNode):
pass
......@@ -2595,6 +2602,7 @@ class PyClassDefNode(ClassDefNode):
self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
if self.doc and Options.docstrings:
doc = embed_position(self.pos, self.doc)
# FIXME: correct string node?
doc_node = ExprNodes.StringNode(pos, value = doc)
else:
doc_node = None
......@@ -3200,7 +3208,7 @@ class InPlaceAssignmentNode(AssignmentNode):
c_op = "/"
elif c_op == "**":
error(self.pos, "No C inplace power operator")
elif self.lhs.type.is_complex and not code.globalstate.directives['c99_complex']:
elif self.lhs.type.is_complex:
error(self.pos, "Inplace operators not implemented for complex types.")
# have to do assignment directly to avoid side-effects
......@@ -3271,6 +3279,10 @@ class InPlaceAssignmentNode(AssignmentNode):
self.rhs.annotate(code)
self.dup.annotate(code)
def create_binop_node(self):
import ExprNodes
return ExprNodes.binop_node(self.pos, self.operator, self.lhs, self.rhs)
class PrintStatNode(StatNode):
# print statement
......@@ -3520,7 +3532,6 @@ class RaiseStatNode(StatNode):
self.exc_tb.analyse_types(env)
self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
nogil_check = Node.gil_error
gil_message = "Raising exception"
......@@ -3541,15 +3552,11 @@ class RaiseStatNode(StatNode):
tb_code = self.exc_tb.py_result()
else:
tb_code = "0"
if self.exc_type or self.exc_value or self.exc_tb:
code.putln(
"__Pyx_Raise(%s, %s, %s);" % (
type_code,
value_code,
tb_code))
else:
code.putln(
"__Pyx_ReRaise();")
for obj in (self.exc_type, self.exc_value, self.exc_tb):
if obj:
obj.generate_disposal_code(code)
......@@ -3571,7 +3578,6 @@ class ReraiseStatNode(StatNode):
child_attrs = []
def analyse_expressions(self, env):
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
nogil_check = Node.gil_error
......@@ -3580,7 +3586,12 @@ class ReraiseStatNode(StatNode):
def generate_execution_code(self, code):
vars = code.funcstate.exc_vars
if vars:
code.putln("__Pyx_Raise(%s, %s, %s);" % tuple(vars))
for varname in vars:
code.put_giveref(varname)
code.putln("__Pyx_ErrRestore(%s, %s, %s);" % tuple(vars))
for varname in vars:
code.put("%s = 0; " % varname)
code.putln()
code.putln(code.error_goto(self.pos))
else:
error(self.pos, "Reraise not inside except clause")
......@@ -4190,8 +4201,9 @@ class TryExceptStatNode(StatNode):
code.put_goto(try_end_label)
if code.label_used(try_return_label):
code.put_label(try_return_label)
for var in Naming.exc_save_vars:
code.put_xdecref_clear(var, py_object_type)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label)
code.put_label(our_error_label)
for temp_name, type in temps_to_clean_up:
......@@ -4203,30 +4215,21 @@ class TryExceptStatNode(StatNode):
if error_label_used or not self.has_default_clause:
if error_label_used:
code.put_label(except_error_label)
for var in Naming.exc_save_vars:
code.put_xdecref(var, py_object_type)
code.put_goto(old_error_label)
if code.label_used(try_break_label):
code.put_label(try_break_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_break_label)
code.put_goto(old_error_label)
if code.label_used(try_continue_label):
code.put_label(try_continue_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_continue_label)
for exit_label, old_label in zip(
[try_break_label, try_continue_label, except_return_label],
[old_break_label, old_continue_label, old_return_label]):
if code.label_used(except_return_label):
code.put_label(except_return_label)
if code.label_used(exit_label):
code.put_label(exit_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label)
code.put_goto(old_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
......@@ -4751,7 +4754,7 @@ class FromImportStatNode(StatNode):
def analyse_expressions(self, env):
import ExprNodes
self.module.analyse_expressions(env)
self.item = ExprNodes.PyTempNode(self.pos, env)
self.item = ExprNodes.RawCNameExprNode(self.pos, py_object_type)
self.interned_items = []
for name, target in self.items:
if name == '*':
......@@ -4779,25 +4782,25 @@ class FromImportStatNode(StatNode):
Naming.import_star,
self.module.py_result(),
code.error_goto(self.pos)))
self.item.allocate(code)
item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
self.item.set_cname(item_temp)
for name, target, coerced_item in self.interned_items:
cname = code.intern_identifier(name)
code.putln(
'%s = PyObject_GetAttr(%s, %s); %s' % (
self.item.result(),
item_temp,
self.module.py_result(),
cname,
code.error_goto_if_null(self.item.result(), self.pos)))
code.put_gotref(self.item.py_result())
code.error_goto_if_null(item_temp, self.pos)))
code.put_gotref(item_temp)
if coerced_item is None:
target.generate_assignment_code(self.item, code)
else:
coerced_item.allocate_temp_result(code)
coerced_item.generate_result_code(code)
target.generate_assignment_code(coerced_item, code)
if self.item.result() != coerced_item.result():
code.put_decref_clear(self.item.result(), self.item.type)
self.item.release(code)
code.put_decref_clear(item_temp, py_object_type)
code.funcstate.release_temp(item_temp)
self.module.generate_disposal_code(code)
self.module.free_temps(code)
......@@ -4819,7 +4822,7 @@ utility_function_predeclarations = \
#define INLINE
#endif
typedef struct {PyObject **p; char *s; long n; char is_unicode; char intern; char is_identifier;} __Pyx_StringTabEntry; /*proto*/
typedef struct {PyObject **p; char *s; const long n; const char* encoding; const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; /*proto*/
"""
......@@ -4994,13 +4997,57 @@ requires=[printing_utility_code])
#------------------------------------------------------------------------------------
# The following function is based on do_raise() from ceval.c.
# Exception raising code
#
# Exceptions are raised by __Pyx_Raise() and stored as plain
# type/value/tb in PyThreadState->curexc_*. When being caught by an
# 'except' statement, curexc_* is moved over to exc_* by
# __Pyx_GetException()
restore_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
""")
# The following function is based on do_raise() from ceval.c. There
# are separate versions for Python2 and Python3 as exception handling
# has changed quite a lot between the two versions.
raise_utility_code = UtilityCode(
proto = """
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
#if PY_MAJOR_VERSION < 3
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
Py_XINCREF(type);
Py_XINCREF(value);
......@@ -5056,6 +5103,7 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
}
#endif
}
__Pyx_ErrRestore(type, value, tb);
return;
raise_error:
......@@ -5064,26 +5112,162 @@ raise_error:
Py_XDECREF(tb);
return;
}
#else // Python 3+
static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
if (tb == Py_None) {
tb = 0;
} else if (tb && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"raise: arg 3 must be a traceback or None");
goto bad;
}
if (value == Py_None)
value = 0;
if (PyExceptionInstance_Check(type)) {
if (value) {
PyErr_SetString(PyExc_TypeError,
"instance exception may not have a separate value");
goto bad;
}
value = type;
type = (PyObject*) Py_TYPE(value);
} else if (!PyExceptionClass_Check(type)) {
PyErr_SetString(PyExc_TypeError,
"raise: exception class must be a subclass of BaseException");
goto bad;
}
PyErr_SetObject(type, value);
if (tb) {
PyThreadState *tstate = PyThreadState_GET();
PyObject* tmp_tb = tstate->curexc_traceback;
if (tb != tmp_tb) {
Py_INCREF(tb);
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_tb);
}
}
bad:
return;
}
#endif
""",
requires=[restore_exception_utility_code])
#------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *local_type, *local_value, *local_tb;
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
local_type = tstate->curexc_type;
local_value = tstate->curexc_value;
local_tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
PyErr_NormalizeException(&local_type, &local_value, &local_tb);
if (unlikely(tstate->curexc_type))
goto bad;
#if PY_MAJOR_VERSION >= 3
if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0))
goto bad;
#endif
*type = local_type;
*value = local_value;
*tb = local_tb;
Py_INCREF(local_type);
Py_INCREF(local_value);
Py_INCREF(local_tb);
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = local_type;
tstate->exc_value = local_value;
tstate->exc_traceback = local_tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
return 0;
bad:
*type = 0;
*value = 0;
*tb = 0;
Py_XDECREF(local_type);
Py_XDECREF(local_value);
Py_XDECREF(local_tb);
return -1;
}
""")
#------------------------------------------------------------------------------------
reraise_utility_code = UtilityCode(
get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
""",
# I doubt that calling __Pyx_GetException() here is correct as it moves
# the exception from tstate->curexc_* to tstate->exc_*, which prevents
# exception handlers later on from receiving it.
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL;
if (__Pyx_GetException(&type, &value, &tb) == 0) {
PyObject* exc_info = PyTuple_New(3);
if (exc_info) {
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyTuple_SET_ITEM(exc_info, 0, type);
PyTuple_SET_ITEM(exc_info, 1, value);
PyTuple_SET_ITEM(exc_info, 2, tb);
return exc_info;
}
}
return NULL;
}
""",
requires=[get_exception_utility_code])
#------------------------------------------------------------------------------------
reset_exception_utility_code = UtilityCode(
proto = """
static void __Pyx_ReRaise(void); /*proto*/
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
static void __Pyx_ReRaise(void) {
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
PyObject* tmp_type = tstate->curexc_type;
PyObject* tmp_value = tstate->curexc_value;
PyObject* tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = tstate->exc_type;
tstate->curexc_value = tstate->exc_value;
tstate->curexc_traceback = tstate->exc_traceback;
tstate->exc_type = 0;
tstate->exc_value = 0;
tstate->exc_traceback = 0;
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
......@@ -5437,57 +5621,6 @@ bad:
'EMPTY_BYTES' : Naming.empty_bytes,
})
restore_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
#if PY_MAJOR_VERSION >= 3
/* Note: this is a temporary work-around to prevent crashes in Python 3.0 */
if ((tstate->exc_type != NULL) & (tstate->exc_type != Py_None)) {
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
PyErr_NormalizeException(&type, &value, &tb);
PyErr_NormalizeException(&tmp_type, &tmp_value, &tmp_tb);
tstate->exc_type = 0;
tstate->exc_value = 0;
tstate->exc_traceback = 0;
PyException_SetContext(value, tmp_value);
Py_DECREF(tmp_type);
Py_XDECREF(tmp_tb);
}
#endif
tmp_type = tstate->curexc_type;
tmp_value = tstate->curexc_value;
tmp_tb = tstate->curexc_traceback;
tstate->curexc_type = type;
tstate->curexc_value = value;
tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
}
""")
#------------------------------------------------------------------------------------
unraisable_exception_utility_code = UtilityCode(
......@@ -5523,22 +5656,20 @@ static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
""",
impl = """
static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
PyObject *pycobj = 0;
int result;
pycobj = PyCObject_FromVoidPtr(vtable, 0);
if (!pycobj)
#if PY_VERSION_HEX < 0x03010000
PyObject *ob = PyCObject_FromVoidPtr(vtable, 0);
#else
PyObject *ob = PyCapsule_New(vtable, 0, 0);
#endif
if (!ob)
goto bad;
if (PyDict_SetItemString(dict, "__pyx_vtable__", pycobj) < 0)
if (PyDict_SetItemString(dict, "__pyx_vtable__", ob) < 0)
goto bad;
result = 0;
goto done;
Py_DECREF(ob);
return 0;
bad:
result = -1;
done:
Py_XDECREF(pycobj);
return result;
Py_XDECREF(ob);
return -1;
}
""")
......@@ -5550,23 +5681,21 @@ static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
""",
impl = r"""
static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
int result;
PyObject *pycobj;
pycobj = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!pycobj)
PyObject *ob = PyMapping_GetItemString(dict, (char *)"__pyx_vtable__");
if (!ob)
goto bad;
*(void **)vtabptr = PyCObject_AsVoidPtr(pycobj);
#if PY_VERSION_HEX < 0x03010000
*(void **)vtabptr = PyCObject_AsVoidPtr(ob);
#else
*(void **)vtabptr = PyCapsule_GetPointer(ob, 0);
#endif
if (!*(void **)vtabptr)
goto bad;
result = 0;
goto done;
Py_DECREF(ob);
return 0;
bad:
result = -1;
done:
Py_XDECREF(pycobj);
return result;
Py_XDECREF(ob);
return -1;
}
""")
......@@ -5580,7 +5709,7 @@ impl = """
static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
while (t->p) {
#if PY_MAJOR_VERSION < 3
if (t->is_unicode && (!t->is_identifier)) {
if (t->is_unicode) {
*t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL);
} else if (t->intern) {
*t->p = PyString_InternFromString(t->s);
......@@ -5588,10 +5717,14 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
*t->p = PyString_FromStringAndSize(t->s, t->n - 1);
}
#else /* Python 3+ has unicode identifiers */
if (t->is_identifier || (t->is_unicode && t->intern)) {
if (t->is_unicode | t->is_str) {
if (t->intern) {
*t->p = PyUnicode_InternFromString(t->s);
} else if (t->is_unicode) {
} else if (t->encoding) {
*t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL);
} else {
*t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1);
}
} else {
*t->p = PyBytes_FromStringAndSize(t->s, t->n - 1);
}
......@@ -5606,107 +5739,6 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
#------------------------------------------------------------------------------------
get_exception_utility_code = UtilityCode(
proto = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
""",
impl = """
static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->curexc_type;
*value = tstate->curexc_value;
*tb = tstate->curexc_traceback;
tstate->curexc_type = 0;
tstate->curexc_value = 0;
tstate->curexc_traceback = 0;
PyErr_NormalizeException(type, value, tb);
if (PyErr_Occurred())
goto bad;
Py_INCREF(*type);
Py_INCREF(*value);
Py_INCREF(*tb);
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = *type;
tstate->exc_value = *value;
tstate->exc_traceback = *tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
return 0;
bad:
Py_XDECREF(*type);
Py_XDECREF(*value);
Py_XDECREF(*tb);
return -1;
}
""")
#------------------------------------------------------------------------------------
get_exception_tuple_utility_code = UtilityCode(proto="""
static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetExceptionTuple(void) {
PyObject *type = NULL, *value = NULL, *tb = NULL;
if (__Pyx_GetException(&type, &value, &tb) == 0) {
PyObject* exc_info = PyTuple_New(3);
if (exc_info) {
Py_INCREF(type);
Py_INCREF(value);
Py_INCREF(tb);
PyTuple_SET_ITEM(exc_info, 0, type);
PyTuple_SET_ITEM(exc_info, 1, value);
PyTuple_SET_ITEM(exc_info, 2, tb);
return exc_info;
}
}
return NULL;
}
""",
requires=[get_exception_utility_code])
#------------------------------------------------------------------------------------
reset_exception_utility_code = UtilityCode(
proto = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
""",
impl = """
static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
*type = tstate->exc_type;
*value = tstate->exc_value;
*tb = tstate->exc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
}
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback;
tstate->exc_type = type;
tstate->exc_value = value;
tstate->exc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
}
""")
#------------------------------------------------------------------------------------
force_init_threads_utility_code = UtilityCode(
proto="""
#ifndef __PYX_FORCE_INIT_THREADS
......
......@@ -20,6 +20,11 @@ try:
except NameError:
from functools import reduce
try:
set
except NameError:
from sets import Set as set
def unwrap_node(node):
while isinstance(node, UtilNodes.ResultRefNode):
node = node.expression
......@@ -224,7 +229,7 @@ class IterationTransform(Visitor.VisitorTransform):
bound2 = args[1].coerce_to_integer(self.current_scope)
step = step.coerce_to_integer(self.current_scope)
if not isinstance(bound2, ExprNodes.ConstNode):
if not bound2.is_literal:
# stop bound must be immutable => keep it in a temp var
bound2_is_temp = True
bound2 = UtilNodes.LetRefNode(bound2)
......@@ -416,12 +421,12 @@ class SwitchTransform(Visitor.VisitorTransform):
and cond.operator == '=='
and not cond.is_python_comparison()):
if is_common_value(cond.operand1, cond.operand1):
if isinstance(cond.operand2, ExprNodes.ConstNode):
if cond.operand2.is_literal:
return cond.operand1, [cond.operand2]
elif hasattr(cond.operand2, 'entry') and cond.operand2.entry and cond.operand2.entry.is_const:
return cond.operand1, [cond.operand2]
if is_common_value(cond.operand2, cond.operand2):
if isinstance(cond.operand1, ExprNodes.ConstNode):
if cond.operand1.is_literal:
return cond.operand2, [cond.operand1]
elif hasattr(cond.operand1, 'entry') and cond.operand1.entry and cond.operand1.entry.is_const:
return cond.operand2, [cond.operand1]
......@@ -517,6 +522,46 @@ class FlattenInListTransform(Visitor.VisitorTransform, SkipDeclarations):
visit_Node = Visitor.VisitorTransform.recurse_to_children
class DropRefcountingTransform(Visitor.VisitorTransform):
"""Drop ref-counting in safe places.
"""
visit_Node = Visitor.VisitorTransform.recurse_to_children
def visit_ParallelAssignmentNode(self, node):
left, right, temps = [], [], []
for stat in node.stats:
if isinstance(stat, Nodes.SingleAssignmentNode):
lhs = unwrap_node(stat.lhs)
if not isinstance(lhs, ExprNodes.NameNode):
return node
left.append(lhs)
rhs = unwrap_node(stat.rhs)
if isinstance(rhs, ExprNodes.CoerceToTempNode):
temps.append(rhs)
rhs = rhs.arg
if not isinstance(rhs, ExprNodes.NameNode):
return node
right.append(rhs)
else:
return node
for name_node in left + right:
if name_node.entry.is_builtin or name_node.entry.is_pyglobal:
return node
left_names = [n.name for n in left]
right_names = [n.name for n in right]
if set(left_names) != set(right_names):
return node
if len(set(left_names)) != len(right):
return node
for name_node in left + right + temps:
name_node.use_managed_ref = False
return node
class OptimizeBuiltinCalls(Visitor.VisitorTransform):
"""Optimize some common methods calls and instantiation patterns
for builtin types.
......@@ -853,10 +898,11 @@ class OptimizeBuiltinCalls(Visitor.VisitorTransform):
encoding_node = args[1]
if isinstance(encoding_node, ExprNodes.CoerceToPyTypeNode):
encoding_node = encoding_node.arg
if not isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode)):
if not isinstance(encoding_node, (ExprNodes.UnicodeNode, ExprNodes.StringNode,
ExprNodes.BytesNode)):
return node
encoding = encoding_node.value
encoding_node = ExprNodes.StringNode(encoding_node.pos, value=encoding,
encoding_node = ExprNodes.BytesNode(encoding_node.pos, value=encoding,
type=PyrexTypes.c_char_ptr_type)
if len(args) == 3:
......@@ -864,13 +910,14 @@ class OptimizeBuiltinCalls(Visitor.VisitorTransform):
if isinstance(error_handling_node, ExprNodes.CoerceToPyTypeNode):
error_handling_node = error_handling_node.arg
if not isinstance(error_handling_node,
(ExprNodes.UnicodeNode, ExprNodes.StringNode)):
(ExprNodes.UnicodeNode, ExprNodes.StringNode,
ExprNodes.BytesNode)):
return node
error_handling = error_handling_node.value
if error_handling == 'strict':
error_handling_node = null_node
else:
error_handling_node = ExprNodes.StringNode(
error_handling_node = ExprNodes.BytesNode(
error_handling_node.pos, value=error_handling,
type=PyrexTypes.c_char_ptr_type)
else:
......@@ -887,7 +934,7 @@ class OptimizeBuiltinCalls(Visitor.VisitorTransform):
else:
value = BytesLiteral(value)
value.encoding = encoding
return ExprNodes.StringNode(
return ExprNodes.BytesNode(
string_node.pos, value=value, type=Builtin.bytes_type)
if error_handling == 'strict':
......@@ -1030,8 +1077,7 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
# the compiler, but we do not aggregate them into a
# constant node to prevent any loss of precision.
return node
if not isinstance(node.operand1, ExprNodes.ConstNode) or \
not isinstance(node.operand2, ExprNodes.ConstNode):
if not node.operand1.is_literal or not node.operand2.is_literal:
# We calculate other constants to make them available to
# the compiler, but we only aggregate constant nodes
# recursively, so non-const nodes are straight out.
......
......@@ -55,7 +55,7 @@ embed = False
# Declare compiler directives
option_defaults = {
directive_defaults = {
'boundscheck' : True,
'nonecheck' : False,
'embedsignature' : False,
......@@ -65,9 +65,10 @@ option_defaults = {
'cdivision_warnings': False,
'always_allow_keywords': False,
'wraparound' : True,
'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "",
'profile': False,
'infer_types': False,
'autotestdict': True,
# test support
......@@ -76,35 +77,35 @@ option_defaults = {
}
# Override types possibilities above, if needed
option_types = {}
directive_types = {}
for key, val in option_defaults.items():
if key not in option_types:
option_types[key] = type(val)
for key, val in directive_defaults.items():
if key not in directive_types:
directive_types[key] = type(val)
option_scopes = { # defaults to available everywhere
directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement'
'autotestdict' : ('module',),
'test_assert_path_exists' : ('function',),
'test_fail_if_path_exists' : ('function',),
}
def parse_option_value(name, value):
def parse_directive_value(name, value):
"""
Parses value as an option value for the given name and returns
the interpreted value. None is returned if the option does not exist.
>>> print parse_option_value('nonexisting', 'asdf asdfd')
>>> print parse_directive_value('nonexisting', 'asdf asdfd')
None
>>> parse_option_value('boundscheck', 'True')
>>> parse_directive_value('boundscheck', 'True')
True
>>> parse_option_value('boundscheck', 'true')
>>> parse_directive_value('boundscheck', 'true')
Traceback (most recent call last):
...
ValueError: boundscheck directive must be set to True or False
"""
type = option_types.get(name)
type = directive_types.get(name)
if not type: return None
if type is bool:
if value == "True": return True
......@@ -118,25 +119,25 @@ def parse_option_value(name, value):
else:
assert False
def parse_option_list(s):
def parse_directive_list(s):
"""
Parses a comma-seperated list of pragma options. Whitespace
is not considered.
>>> parse_option_list(' ')
>>> parse_directive_list(' ')
{}
>>> (parse_option_list('boundscheck=True') ==
>>> (parse_directive_list('boundscheck=True') ==
... {'boundscheck': True})
True
>>> parse_option_list(' asdf')
>>> parse_directive_list(' asdf')
Traceback (most recent call last):
...
ValueError: Expected "=" in option "asdf"
>>> parse_option_list('boundscheck=hey')
>>> parse_directive_list('boundscheck=hey')
Traceback (most recent call last):
...
ValueError: Must pass a boolean value for option "boundscheck"
>>> parse_option_list('unknown=True')
>>> parse_directive_list('unknown=True')
Traceback (most recent call last):
...
ValueError: Unknown option: "unknown"
......@@ -148,7 +149,7 @@ def parse_option_list(s):
if not '=' in item: raise ValueError('Expected "=" in option "%s"' % item)
name, value = item.strip().split('=')
try:
type = option_types[name]
type = directive_types[name]
except KeyError:
raise ValueError('Unknown option: "%s"' % name)
if type is bool:
......
......@@ -153,10 +153,10 @@ class PostParse(CythonTransform):
- For __cythonbufferdefaults__ the arguments are checked for
validity.
CBufferAccessTypeNode has its options interpreted:
CBufferAccessTypeNode has its directives interpreted:
Any first positional argument goes into the "dtype" attribute,
any "ndim" keyword argument goes into the "ndim" attribute and
so on. Also it is checked that the option combination is valid.
so on. Also it is checked that the directive combination is valid.
- __cythonbufferdefaults__ attributes are parsed and put into the
type information.
......@@ -324,14 +324,14 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
"""
After parsing, options can be stored in a number of places:
After parsing, directives can be stored in a number of places:
- #cython-comments at the top of the file (stored in ModuleNode)
- Command-line arguments overriding these
- @cython.optionname decorators
- with cython.optionname: statements
- @cython.directivename decorators
- with cython.directivename: statements
This transform is responsible for interpreting these various sources
and store the option in two ways:
and store the directive in two ways:
- Set the directives attribute of the ModuleNode for global directives.
- Use a CompilerDirectivesNode to override directives for a subtree.
......@@ -348,18 +348,18 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
duplication of functionality has to occur: We manually track cimports
and which names the "cython" module may have been imported to.
"""
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'cast', 'address', 'pointer', 'compiled', 'NULL'])
special_methods = set(['declare', 'union', 'struct', 'typedef', 'sizeof', 'typeof', 'cast', 'address', 'pointer', 'compiled', 'NULL'])
def __init__(self, context, compilation_option_overrides):
def __init__(self, context, compilation_directive_defaults):
super(InterpretCompilerDirectives, self).__init__(context)
self.compilation_option_overrides = {}
for key, value in compilation_option_overrides.iteritems():
self.compilation_option_overrides[unicode(key)] = value
self.compilation_directive_defaults = {}
for key, value in compilation_directive_defaults.iteritems():
self.compilation_directive_defaults[unicode(key)] = value
self.cython_module_names = set()
self.option_names = {}
self.directive_names = {}
def check_directive_scope(self, pos, directive, scope):
legal_scopes = Options.option_scopes.get(directive, None)
legal_scopes = Options.directive_scopes.get(directive, None)
if legal_scopes and scope not in legal_scopes:
self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive '
'is not allowed in %s scope' % (directive, scope)))
......@@ -369,19 +369,16 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# Set up processing and handle the cython: comments.
def visit_ModuleNode(self, node):
options = copy.copy(Options.option_defaults)
for key, value in self.compilation_option_overrides.iteritems():
for key, value in node.directive_comments.iteritems():
if not self.check_directive_scope(node.pos, key, 'module'):
self.wrong_scope_error(node.pos, key, 'module')
del self.compilation_option_overrides[key]
continue
if key in node.option_comments and node.option_comments[key] != value:
warning(node.pos, "Compiler directive differs between environment and file header; this will change "
"in Cython 0.12. See http://article.gmane.org/gmane.comp.python.cython.devel/5233", 2)
options.update(node.option_comments)
options.update(self.compilation_option_overrides)
self.options = options
node.directives = options
del node.directive_comments[key]
directives = copy.copy(Options.directive_defaults)
directives.update(self.compilation_directive_defaults)
directives.update(node.directive_comments)
self.directives = directives
node.directives = directives
self.visitchildren(node)
node.cython_module_names = self.cython_module_names
return node
......@@ -400,15 +397,15 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
if node.module_name == u"cython":
newimp = []
for pos, name, as_name, kind in node.imported_names:
if (name in Options.option_types or
if (name in Options.directive_types or
name in self.special_methods or
PyrexTypes.parse_basic_type(name)):
if as_name is None:
as_name = name
self.option_names[as_name] = name
self.directive_names[as_name] = name
if kind is not None:
self.context.nonfatal_error(PostParseError(pos,
"Compiler option imports must be plain imports"))
"Compiler directive imports must be plain imports"))
else:
newimp.append((pos, name, as_name, kind))
if not newimp:
......@@ -420,10 +417,10 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
if node.module.module_name.value == u"cython":
newimp = []
for name, name_node in node.items:
if (name in Options.option_types or
if (name in Options.directive_types or
name in self.special_methods or
PyrexTypes.parse_basic_type(name)):
self.option_names[name_node.name] = name
self.directive_names[name_node.name] = name
else:
newimp.append((name, name_node))
if not newimp:
......@@ -446,12 +443,12 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
if node.name in self.cython_module_names:
node.is_cython_module = True
else:
node.cython_attribute = self.option_names.get(node.name)
node.cython_attribute = self.directive_names.get(node.name)
return node
def try_to_parse_option(self, node):
# If node is the contents of an option (in a with statement or
# decorator), returns (optionname, value).
def try_to_parse_directive(self, node):
# If node is the contents of an directive (in a with statement or
# decorator), returns (directivename, value).
# Otherwise, returns None
optname = None
if isinstance(node, CallNode):
......@@ -459,56 +456,56 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
optname = node.function.as_cython_attribute()
if optname:
optiontype = Options.option_types.get(optname)
if optiontype:
directivetype = Options.directive_types.get(optname)
if directivetype:
args, kwds = node.explicit_args_kwds()
if optiontype is bool:
if directivetype is bool:
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
raise PostParseError(dec.function.pos,
'The %s option takes one compile-time boolean argument' % optname)
raise PostParseError(node.function.pos,
'The %s directive takes one compile-time boolean argument' % optname)
return (optname, args[0].value)
elif optiontype is str:
if kwds is not None or len(args) != 1 or not isinstance(args[0], StringNode):
raise PostParseError(dec.function.pos,
'The %s option takes one compile-time string argument' % optname)
elif directivetype is str:
if kwds is not None or len(args) != 1 or not isinstance(args[0], (StringNode, UnicodeNode)):
raise PostParseError(node.function.pos,
'The %s directive takes one compile-time string argument' % optname)
return (optname, str(args[0].value))
elif optiontype is dict:
elif directivetype is dict:
if len(args) != 0:
raise PostParseError(dec.function.pos,
'The %s option takes no prepositional arguments' % optname)
raise PostParseError(node.function.pos,
'The %s directive takes no prepositional arguments' % optname)
return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
elif optiontype is list:
elif directivetype is list:
if kwds and len(kwds) != 0:
raise PostParseError(dec.function.pos,
'The %s option takes no keyword arguments' % optname)
raise PostParseError(node.function.pos,
'The %s directive takes no keyword arguments' % optname)
return optname, [ str(arg.value) for arg in args ]
else:
assert False
return None
def visit_with_options(self, body, options):
oldoptions = self.options
newoptions = copy.copy(oldoptions)
newoptions.update(options)
self.options = newoptions
def visit_with_directives(self, body, directives):
olddirectives = self.directives
newdirectives = copy.copy(olddirectives)
newdirectives.update(directives)
self.directives = newdirectives
assert isinstance(body, StatListNode), body
retbody = self.visit_Node(body)
directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody,
directives=newoptions)
self.options = oldoptions
directives=newdirectives)
self.directives = olddirectives
return directive
# Handle decorators
def visit_FuncDefNode(self, node):
options = []
directives = []
if node.decorators:
# Split the decorators into two lists -- real decorators and options
# Split the decorators into two lists -- real decorators and directives
realdecs = []
for dec in node.decorators:
option = self.try_to_parse_option(dec.decorator)
if option is not None:
options.append(option)
directive = self.try_to_parse_directive(dec.decorator)
if directive is not None:
directives.append(directive)
else:
realdecs.append(dec)
if realdecs and isinstance(node, CFuncDefNode):
......@@ -516,12 +513,12 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
else:
node.decorators = realdecs
if options:
if directives:
optdict = {}
options.reverse() # Decorators coming first take precedence
for option in options:
name, value = option
legal_scopes = Options.option_scopes.get(name, None)
directives.reverse() # Decorators coming first take precedence
for directive in directives:
name, value = directive
legal_scopes = Options.directive_scopes.get(name, None)
if not self.check_directive_scope(node.pos, name, 'function'):
continue
if name in optdict:
......@@ -537,16 +534,16 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
else:
optdict[name] = value
body = StatListNode(node.pos, stats=[node])
return self.visit_with_options(body, optdict)
return self.visit_with_directives(body, optdict)
else:
return self.visit_Node(node)
def visit_CVarDefNode(self, node):
if node.decorators:
for dec in node.decorators:
option = self.try_to_parse_option(dec.decorator)
if option is not None and option[0] == u'locals':
node.directive_locals = option[1]
directive = self.try_to_parse_directive(dec.decorator)
if directive is not None and directive[0] == u'locals':
node.directive_locals = directive[1]
else:
self.context.nonfatal_error(PostParseError(dec.pos,
"Cdef functions can only take cython.locals() decorator."))
......@@ -555,15 +552,15 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# Handle with statements
def visit_WithStatNode(self, node):
option = self.try_to_parse_option(node.manager)
if option is not None:
directive = self.try_to_parse_directive(node.manager)
if directive is not None:
if node.target is not None:
self.context.nonfatal_error(
PostParseError(node.pos, "Compiler option with statements cannot contain 'as'"))
PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
else:
name, value = option
name, value = directive
if self.check_directive_scope(node.pos, name, 'with statement'):
return self.visit_with_options(node.body, {name:value})
return self.visit_with_directives(node.body, {name:value})
return self.visit_Node(node)
class WithTransform(CythonTransform, SkipDeclarations):
......@@ -810,11 +807,13 @@ property NAME:
class AnalyseExpressionsTransform(CythonTransform):
def visit_ModuleNode(self, node):
node.scope.infer_types()
node.body.analyse_expressions(node.scope)
self.visitchildren(node)
return node
def visit_FuncDefNode(self, node):
node.local_scope.infer_types()
node.body.analyse_expressions(node.local_scope)
self.visitchildren(node)
return node
......@@ -1027,7 +1026,7 @@ class TransformBuiltinMethods(EnvTransform):
pos = node.pos
lenv = self.env_stack[-1]
items = [ExprNodes.DictItemNode(pos,
key=ExprNodes.IdentifierStringNode(pos, value=var),
key=ExprNodes.StringNode(pos, value=var),
value=ExprNodes.NameNode(pos, name=var)) for var in lenv.entries]
return ExprNodes.DictNode(pos, key_value_pairs=items)
......@@ -1052,6 +1051,11 @@ class TransformBuiltinMethods(EnvTransform):
node = SizeofTypeNode(node.function.pos, arg_type=type)
else:
node = SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'typeof':
if len(node.args) != 1:
error(node.function.pos, u"sizeof takes exactly one argument" % function)
else:
node = TypeofNode(node.function.pos, operand=node.args[0])
elif function == 'address':
if len(node.args) != 1:
error(node.function.pos, u"sizeof takes exactly one argument" % function)
......
......@@ -14,7 +14,7 @@ from Cython.Compiler.Scanning import PyrexScanner, FileSourceDescriptor
import Nodes
import ExprNodes
import StringEncoding
from StringEncoding import EncodedString, BytesLiteral, _str, _bytes
from StringEncoding import EncodedString, BytesLiteral, _unicode, _bytes
from ModuleNode import ModuleNode
from Errors import error, warning, InternalError
from Cython import Utils
......@@ -387,8 +387,7 @@ def p_call(s, function):
s.error("Expected an identifier before '='",
pos = arg.pos)
encoded_name = EncodedString(arg.name)
keyword = ExprNodes.IdentifierStringNode(arg.pos,
value = encoded_name)
keyword = ExprNodes.IdentifierStringNode(arg.pos, value = encoded_name)
arg = p_simple_expr(s)
keyword_args.append((keyword, arg))
else:
......@@ -579,6 +578,8 @@ def p_atom(s):
return ExprNodes.CharNode(pos, value = value)
elif kind == 'u':
return ExprNodes.UnicodeNode(pos, value = value)
elif kind == 'b':
return ExprNodes.BytesNode(pos, value = value)
else:
return ExprNodes.StringNode(pos, value = value)
elif sy == 'IDENT':
......@@ -610,8 +611,10 @@ def p_name(s, name):
return ExprNodes.IntNode(pos, value = rep, longness = "L")
elif isinstance(value, float):
return ExprNodes.FloatNode(pos, value = rep)
elif isinstance(value, (_str, _bytes)):
return ExprNodes.StringNode(pos, value = value)
elif isinstance(value, _unicode):
return ExprNodes.UnicodeNode(pos, value = value)
elif isinstance(value, _bytes):
return ExprNodes.BytesNode(pos, value = value)
else:
error(pos, "Invalid type for compile-time constant: %s"
% value.__class__.__name__)
......@@ -619,24 +622,20 @@ def p_name(s, name):
def p_cat_string_literal(s):
# A sequence of one or more adjacent string literals.
# Returns (kind, value) where kind in ('b', 'c', 'u')
# Returns (kind, value) where kind in ('b', 'c', 'u', '')
kind, value = p_string_literal(s)
if s.sy != 'BEGIN_STRING':
return kind, value
if kind != 'c':
strings = [value]
while s.sy == 'BEGIN_STRING':
pos = s.position()
next_kind, next_value = p_string_literal(s)
if next_kind == 'c':
error(s.position(),
"Cannot concatenate char literal with another string or char literal")
error(pos, "Cannot concatenate char literal with another string or char literal")
elif next_kind != kind:
# we have to switch to unicode now
if kind == 'b':
# concatenating a unicode string to byte strings
strings = [u''.join([s.decode(s.encoding) for s in strings])]
elif kind == 'u':
# concatenating a byte string to unicode strings
strings.append(next_value.decode(next_value.encoding))
kind = 'u'
error(pos, "Cannot mix string literals of different types, expected %s'', got %s''" %
(kind, next_kind))
else:
strings.append(next_value)
if kind == 'u':
......@@ -669,8 +668,6 @@ def p_string_literal(s):
if Future.unicode_literals in s.context.future_directives:
if kind == '':
kind = 'u'
elif kind == '':
kind = 'b'
if kind == 'u':
chars = StringEncoding.UnicodeLiteralBuilder()
else:
......@@ -935,7 +932,7 @@ def p_expression_or_assignment(s):
rhs = p_expr(s)
return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs)
expr = expr_list[0]
if isinstance(expr, ExprNodes.StringNode):
if isinstance(expr, (ExprNodes.UnicodeNode, ExprNodes.StringNode, ExprNodes.BytesNode)):
return Nodes.PassStatNode(expr.pos)
else:
return Nodes.ExprStatNode(expr.pos, expr = expr)
......@@ -966,7 +963,7 @@ def flatten_parallel_assignments(input, output):
# individual elements. This transformation is applied
# recursively, so that nested structures get matched as well.
rhs = input[-1]
if not rhs.is_sequence_constructor:
if not rhs.is_sequence_constructor or not sum([lhs.is_sequence_constructor for lhs in input[:-1]]):
output.append(input)
return
......@@ -1170,8 +1167,7 @@ def p_import_statement(s):
else:
if as_name and "." in dotted_name:
name_list = ExprNodes.ListNode(pos, args = [
ExprNodes.IdentifierStringNode(
pos, value = EncodedString("*"))])
ExprNodes.IdentifierStringNode(pos, value = EncodedString("*"))])
else:
name_list = None
stat = Nodes.SingleAssignmentNode(pos,
......@@ -1756,8 +1752,8 @@ def p_positional_and_keyword_args(s, end_sy_set, type_positions=(), type_keyword
parsed_type = True
else:
arg = p_simple_expr(s)
keyword_node = ExprNodes.IdentifierStringNode(arg.pos,
value = EncodedString(ident))
keyword_node = ExprNodes.IdentifierStringNode(
arg.pos, value = EncodedString(ident))
keyword_args.append((keyword_node, arg))
was_keyword = True
else:
......@@ -2628,7 +2624,7 @@ def p_compiler_directive_comments(s):
if m:
name = m.group(1)
try:
value = Options.parse_option_value(str(name), str(m.group(2).strip()))
value = Options.parse_directive_value(str(name), str(m.group(2).strip()))
if value is not None: # can be False!
result[name] = value
except ValueError, e:
......@@ -2639,7 +2635,7 @@ def p_compiler_directive_comments(s):
def p_module(s, pxd, full_module_name):
pos = s.position()
option_comments = p_compiler_directive_comments(s)
directive_comments = p_compiler_directive_comments(s)
s.parse_comments = False
doc = p_doc_string(s)
......@@ -2654,7 +2650,7 @@ def p_module(s, pxd, full_module_name):
repr(s.sy), repr(s.systring)))
return ModuleNode(pos, doc = doc, body = body,
full_module_name = full_module_name,
option_comments = option_comments)
directive_comments = directive_comments)
#----------------------------------------------
#
......
......@@ -77,6 +77,7 @@ class PyrexType(BaseType):
#
is_pyobject = 0
is_unspecified = 0
is_extension_type = 0
is_builtin_type = 0
is_numeric = 0
......@@ -149,6 +150,15 @@ class PyrexType(BaseType):
# type information of the struct.
return 1
def create_typedef_type(cname, base_type, is_external=0):
if base_type.is_complex:
if is_external:
raise ValueError("Complex external typedefs not supported")
return base_type
else:
return CTypedefType(cname, base_type, is_external)
class CTypedefType(BaseType):
#
# Pseudo-type defined with a ctypedef statement in a
......@@ -169,6 +179,7 @@ class CTypedefType(BaseType):
def __init__(self, cname, base_type, is_external=0):
assert not base_type.is_complex
self.typedef_cname = cname
self.typedef_base_type = base_type
self.typedef_is_external = is_external
......@@ -335,7 +346,8 @@ class PyObjectType(PyrexType):
return "<PyObjectType>"
def assignable_from(self, src_type):
return 1 # Conversion will be attempted
# except for pointers, conversion will be attempted
return not src_type.is_ptr or src_type.is_string
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
......@@ -822,7 +834,7 @@ class CFloatType(CNumericType):
class CComplexType(CNumericType):
is_complex = 1
to_py_function = "__pyx_PyObject_from_complex"
to_py_function = "__pyx_PyComplex_FromComplex"
has_attributes = 1
scope = None
......@@ -849,8 +861,18 @@ class CComplexType(CNumericType):
def __hash__(self):
return ~hash(self.real_type)
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)
else:
base = public_decl(self.sign_and_name(), dll_linkage)
return self.base_declaration_code(base, entity_code)
def sign_and_name(self):
return Naming.type_prefix + self.real_type.specalization_name() + "_complex"
real_type_name = self.real_type.specalization_name()
real_type_name = real_type_name.replace('long__double','long_double')
return Naming.type_prefix + real_type_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)
......@@ -860,29 +882,53 @@ class CComplexType(CNumericType):
def attributes_known(self):
if self.scope is None:
import Symtab
self.scope = Symtab.StructOrUnionScope(self.specalization_name())
self.scope.declare_var("real", self.real_type, None, "real")
self.scope.declare_var("imag", self.real_type, None, "imag")
self.scope = scope = Symtab.CClassScope(
'',
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)
entry = scope.declare_cfunction(
"conjugate",
CFuncType(self, [CFuncTypeArg("self", self, None)]),
pos=None,
defining=1,
cname="__Pyx_c_conj%s" % self.real_type.math_h_modifier)
return True
def create_declaration_utility_code(self, env):
# This must always be run, because a single CComplexType instance can be shared
# across multiple compilations (the one created in the module scope)
env.use_utility_code(complex_generic_utility_code)
env.use_utility_code(complex_header_utility_code)
env.use_utility_code(complex_real_imag_utility_code)
for utility_code in (complex_type_utility_code,
complex_from_parts_utility_code,
complex_arithmatic_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('')))
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.real_type.math_h_modifier))
return True
def create_to_py_utility_code(self, env):
env.use_utility_code(complex_real_imag_utility_code)
env.use_utility_code(complex_to_py_utility_code)
return True
def create_from_py_utility_code(self, env):
self.real_type.create_from_py_utility_code(env)
for utility_code in (complex_from_parts_utility_code,
complex_from_py_utility_code):
env.use_utility_code(
complex_conversion_utility_code.specialize(self,
math_h_modifier = self.real_type.math_h_modifier,
utility_code.specialize(
self,
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()
m = self.real_type.math_h_modifier))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specalization_name()
return True
def lookup_op(self, nargs, op):
......@@ -892,7 +938,8 @@ class CComplexType(CNumericType):
pass
try:
op_name = complex_ops[nargs, op]
self.binops[nargs, op] = func_name = "%s_%s" % (self.specalization_name(), op_name)
modifier = self.real_type.math_h_modifier
self.binops[nargs, op] = func_name = "__Pyx_c_%s%s" % (op_name, modifier)
return func_name
except KeyError:
return None
......@@ -906,114 +953,210 @@ class CComplexType(CNumericType):
complex_ops = {
(1, '-'): 'neg',
(1, 'zero'): 'is_zero',
(2, '+'): 'add',
(2, '-') : 'sub',
(2, '*'): 'mul',
(2, '/'): 'div',
(2, '+'): 'sum',
(2, '-'): 'diff',
(2, '*'): 'prod',
(2, '/'): 'quot',
(2, '=='): 'eq',
}
complex_generic_utility_code = UtilityCode(
complex_header_utility_code = UtilityCode(
proto_block='h_code',
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)
#if !defined(CYTHON_CCOMPLEX)
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#elif defined(_Complex_I)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
#endif
#define __pyx_PyObject_from_complex(z) PyComplex_FromDoubles((double)__Pyx_REAL_PART(z), (double)__Pyx_IMAG_PART(z))
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
#include <complex>
#else
#include <complex.h>
#endif
#endif
""")
complex_conversion_utility_code = UtilityCode(
complex_real_imag_utility_code = UtilityCode(
proto="""
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o); /* proto */
""",
impl="""
static %(type)s __pyx_PyObject_As_%(type_name)s(PyObject* o) {
if (PyComplex_CheckExact(o)) {
return %(type_name)s_from_parts(
(%(real_type)s)((PyComplexObject *)o)->cval.real,
(%(real_type)s)((PyComplexObject *)o)->cval.imag);
}
else {
Py_complex cval = PyComplex_AsCComplex(o);
return %(type_name)s_from_parts((%(real_type)s)cval.real, (%(real_type)s)cval.imag);
}
}
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
#define __Pyx_CREAL(z) ((z).real())
#define __Pyx_CIMAG(z) ((z).imag())
#else
#define __Pyx_CREAL(z) (__real__(z))
#define __Pyx_CIMAG(z) (__imag__(z))
#endif
#else
#define __Pyx_CREAL(z) ((z).real)
#define __Pyx_CIMAG(z) ((z).imag)
#endif
""")
complex_arithmatic_utility_code = UtilityCode(
complex_type_utility_code = UtilityCode(
proto_block='utility_code_proto_before_types',
proto="""
#if __PYX_USE_C99_COMPLEX
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
typedef ::std::complex< %(real_type)s > %(type_name)s;
#else
typedef %(real_type)s _Complex %(type_name)s;
#endif
#else
typedef struct { %(real_type)s real, imag; } %(type_name)s;
#endif
""")
complex_from_parts_utility_code = UtilityCode(
proto_block='utility_code_proto',
proto="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#endif
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s, %(real_type)s);
#endif
""",
impl="""
#if CYTHON_CCOMPLEX
#ifdef __cplusplus
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return ::std::complex< %(real_type)s >(x, y);
}
#else
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
return x + y*(%(type)s)_Complex_I;
}
#define %(type_name)s_is_zero(a) ((a) == 0)
#define %(type_name)s_eq(a, b) ((a) == (b))
#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))
#endif
#else
typedef struct { %(real_type)s real, imag; } %(type_name)s;
static INLINE %(type)s %(type_name)s_from_parts(%(real_type)s x, %(real_type)s y) {
%(type)s c; c.real = x; c.imag = y; return c;
%(type)s z;
z.real = x;
z.imag = y;
return z;
}
#endif
""")
static INLINE int %(type_name)s_is_zero(%(type)s a) {
return (a.real == 0) & (a.imag == 0);
}
complex_to_py_utility_code = UtilityCode(
proto="""
#define __pyx_PyComplex_FromComplex(z) \\
PyComplex_FromDoubles((double)__Pyx_CREAL(z), \\
(double)__Pyx_CIMAG(z))
""")
static INLINE int %(type_name)s_eq(%(type)s a, %(type)s b) {
return (a.real == b.real) & (a.imag == b.imag);
}
complex_from_py_utility_code = UtilityCode(
proto="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject*);
""",
impl="""
static %(type)s __Pyx_PyComplex_As_%(type_name)s(PyObject* o) {
Py_complex cval;
if (PyComplex_CheckExact(o))
cval = ((PyComplexObject *)o)->cval;
else
cval = PyComplex_AsCComplex(o);
return %(type_name)s_from_parts(
(%(real_type)s)cval.real,
(%(real_type)s)cval.imag);
}
""")
static INLINE %(type)s %(type_name)s_add(%(type)s a, %(type)s b) {
complex_arithmatic_utility_code = UtilityCode(
proto="""
#if CYTHON_CCOMPLEX
#define __Pyx_c_eq%(m)s(a, b) ((a)==(b))
#define __Pyx_c_sum%(m)s(a, b) ((a)+(b))
#define __Pyx_c_diff%(m)s(a, b) ((a)-(b))
#define __Pyx_c_prod%(m)s(a, b) ((a)*(b))
#define __Pyx_c_quot%(m)s(a, b) ((a)/(b))
#define __Pyx_c_neg%(m)s(a) (-(a))
#ifdef __cplusplus
#define __Pyx_c_is_zero%(m)s(z) ((z)==0.0)
#define __Pyx_c_conj%(m)s(z) (::std::conj(z))
/*#define __Pyx_c_abs%(m)s(z) (::std::abs(z))*/
#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))*/
#endif
#else
static INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_sum%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_diff%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_prod%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s, %(type)s);
static INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s);
static INLINE int __Pyx_c_is_zero%(m)s(%(type)s);
static INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s);
/*static INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);*/
#endif
""",
impl="""
#if CYTHON_CCOMPLEX
#else
static INLINE int __Pyx_c_eq%(m)s(%(type)s a, %(type)s b) {
return (a.real == b.real) && (a.imag == b.imag);
}
static INLINE %(type)s __Pyx_c_sum%(m)s(%(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) {
static INLINE %(type)s __Pyx_c_diff%(m)s(%(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) {
static INLINE %(type)s __Pyx_c_prod%(m)s(%(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) {
static INLINE %(type)s __Pyx_c_quot%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
%(real_type)s denom = b.real*b.real + b.imag*b.imag;
%(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) {
static INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s a) {
%(type)s z;
z.real = -a.real;
z.imag = -a.imag;
return z;
}
static INLINE int __Pyx_c_is_zero%(m)s(%(type)s a) {
return (a.real == 0) && (a.imag == 0);
}
static INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s a) {
%(type)s z;
z.real = a.real;
z.imag = -a.imag;
return z;
}
/*
static 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
}
*/
#endif
""", proto_block='complex_numbers_utility_code')
""")
class CArrayType(CType):
......@@ -1401,6 +1544,8 @@ class CStructOrUnionType(CType):
# typedef_flag boolean
# packed boolean
# entry Entry
is_struct_or_union = 1
has_attributes = 1
......@@ -1429,8 +1574,7 @@ class CStructOrUnionType(CType):
self.to_py_function = None
self._convert_code = False
return False
entry = env.lookup(self.name)
forward_decl = (entry.visibility != 'extern')
forward_decl = (self.entry.visibility != 'extern')
self._convert_code = StructUtilityCode(self, forward_decl)
env.use_utility_code(self._convert_code)
......@@ -1469,12 +1613,7 @@ class CStructOrUnionType(CType):
return False
def __hash__(self):
try:
return self.__hashval
except AttributeError:
hashval = self.__hashval = hash(self.cname) ^ (sum([
hash(field.name) for field in self.scope.var_entries]) % 0xffff)
return hashval
return hash(self.cname) ^ hash(self.kind)
def is_complete(self):
return self.scope is not None
......@@ -1592,6 +1731,8 @@ class CUCharPtrType(CStringType, CPtrType):
class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined.
is_unspecified = 1
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<unspecified>"
......@@ -1788,6 +1929,23 @@ def widest_numeric_type(type1, type2):
return sign_and_rank_to_type[min(type1.signed, type2.signed), max(type1.rank, type2.rank)]
return widest_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 type1
elif type1.is_numeric and type2.is_numeric:
return widest_numeric_type(type1, type2)
elif type1.is_pyobject ^ type2.is_pyobject:
return py_object_type
elif type1.assignable_from(type2):
return type1
elif type2.assignable_from(type1):
return type2
else:
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.
......@@ -1828,19 +1986,6 @@ def c_ptr_type(base_type):
else:
return CPtrType(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)
......
......@@ -9,6 +9,7 @@ import os
import platform
import stat
import sys
import codecs
from time import time
import cython
......@@ -279,8 +280,12 @@ class FileSourceDescriptor(SourceDescriptor):
self.filename = filename
self._cmp_name = filename
def get_lines(self):
def get_lines(self, encoding=None, error_handling=None):
if not encoding:
return Utils.open_source_file(self.filename)
else:
return codecs.open(self.filename, "rU", encoding=encoding,
errors=error_handling)
def get_description(self):
return self.filename
......@@ -307,8 +312,12 @@ class StringSourceDescriptor(SourceDescriptor):
self.codelines = [x + "\n" for x in code.split("\n")]
self._cmp_name = name
def get_lines(self):
def get_lines(self, encoding=None, error_handling=None):
if not encoding:
return self.codelines
else:
return [ line.encode(encoding, error_handling).decode(encoding)
for line in self.codelines ]
def get_description(self):
return self.name
......@@ -454,7 +463,6 @@ class PyrexScanner(Scanner):
sy = systring
else:
systring = EncodedString(systring)
systring.encoding = self.source_encoding
self.sy = sy
self.systring = systring
if False: # debug_scanner:
......
......@@ -6,14 +6,14 @@ import re
import sys
if sys.version_info[0] >= 3:
_str, _bytes = str, bytes
_unicode, _str, _bytes = str, str, bytes
IS_PYTHON3 = True
else:
_str, _bytes = unicode, str
_unicode, _str, _bytes = unicode, str, str
IS_PYTHON3 = False
empty_bytes = _bytes()
empty_str = _str()
empty_unicode = _unicode()
join_bytes = empty_bytes.join
......@@ -27,7 +27,7 @@ class UnicodeLiteralBuilder(object):
if isinstance(characters, _bytes):
# this came from a Py2 string literal in the parser code
characters = characters.decode("ASCII")
assert isinstance(characters, _str), str(type(characters))
assert isinstance(characters, _unicode), str(type(characters))
self.chars.append(characters)
def append_charval(self, char_number):
......@@ -45,7 +45,7 @@ class BytesLiteralBuilder(object):
self.target_encoding = target_encoding
def append(self, characters):
if isinstance(characters, _str):
if isinstance(characters, _unicode):
characters = characters.encode(self.target_encoding)
assert isinstance(characters, _bytes), str(type(characters))
self.chars.append(characters)
......@@ -63,7 +63,7 @@ class BytesLiteralBuilder(object):
# this *must* return a byte string!
return self.getstring()
class EncodedString(_str):
class EncodedString(_unicode):
# unicode string subclass to keep track of the original encoding.
# 'encoding' is None for unicode strings and the source encoding
# otherwise
......@@ -82,7 +82,7 @@ class EncodedString(_str):
is_unicode = property(is_unicode)
class BytesLiteral(_bytes):
# str subclass that is compatible with EncodedString
# bytes subclass that is compatible with EncodedString
encoding = None
def byteencode(self):
......
......@@ -8,7 +8,7 @@ from Errors import warning, error, InternalError
from StringEncoding import EncodedString
import Options, Naming
import PyrexTypes
from PyrexTypes import py_object_type
from PyrexTypes import py_object_type, unspecified_type
import TypeSlots
from TypeSlots import \
pyfunction_signature, pymethod_signature, \
......@@ -118,6 +118,7 @@ class Entry(object):
# buffer_aux BufferAux or None Extra information needed for buffer variables
# inline_func_in_pxd boolean Hacky special case for inline function in pxd file.
# Ideally this should not be necesarry.
# assignments [ExprNode] List of expressions that get assigned to this entry.
inline_func_in_pxd = False
borrowed = 0
......@@ -173,6 +174,10 @@ class Entry(object):
self.type = type
self.pos = pos
self.init = init
self.assignments = []
def __repr__(self):
return "Entry(name=%s, type=%s)" % (self.name, self.type)
def redeclared(self, pos):
error(pos, "'%s' does not match previous declaration" % self.name)
......@@ -344,7 +349,11 @@ class Scope(object):
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
type = PyrexTypes.CTypedefType(cname, base_type, (visibility == 'extern'))
try:
type = PyrexTypes.create_typedef_type(cname, base_type, (visibility == 'extern'))
except ValueError, e:
error(pos, e.message)
type = PyrexTypes.error_type
entry = self.declare_type(name, type, pos, cname, visibility)
type.qualified_name = entry.qualified_name
return entry
......@@ -365,6 +374,7 @@ class Scope(object):
entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None)
self.sue_entries.append(entry)
type.entry = entry
else:
if not (entry.is_type and entry.type.is_struct_or_union
and entry.type.kind == kind):
......@@ -513,7 +523,7 @@ class Scope(object):
if entry.as_module:
scope = entry.as_module
else:
error(pos, "'%s' is not a cimported module" % scope.qualified_name)
error(pos, "'%s' is not a cimported module" % '.'.join(path))
return None
return scope
......@@ -556,6 +566,10 @@ class Scope(object):
return 1
return 0
def infer_types(self):
from TypeInference import get_type_inferer
get_type_inferer().infer_types(self)
class PreImportScope(Scope):
namespace_cname = Naming.preimport_cname
......@@ -827,6 +841,8 @@ class ModuleScope(Scope):
if not visibility in ('private', 'public', 'extern'):
error(pos, "Module-level variable cannot be declared %s" % visibility)
if not is_cdef:
if type is unspecified_type:
type = py_object_type
if not (type.is_pyobject and not type.is_extension_type):
raise InternalError(
"Non-cdef global variable is not a generic Python object")
......@@ -1057,6 +1073,10 @@ class ModuleScope(Scope):
var_entry.is_readonly = 1
entry.as_variable = var_entry
def infer_types(self):
from TypeInference import PyObjectTypeInferer
PyObjectTypeInferer().infer_types(self)
class LocalScope(Scope):
def __init__(self, name, outer_scope):
......@@ -1087,7 +1107,7 @@ class LocalScope(Scope):
cname, visibility, is_cdef)
if type.is_pyobject and not Options.init_local_none:
entry.init = "0"
entry.init_to_none = type.is_pyobject and Options.init_local_none
entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
entry.is_local = 1
self.var_entries.append(entry)
return entry
......@@ -1188,7 +1208,7 @@ class StructOrUnionScope(Scope):
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()):
self.declare_var(name, type, pos, cname, visibility)
return self.declare_var(name, type, pos, cname, visibility)
class ClassScope(Scope):
# Abstract base class for namespace of
......@@ -1235,6 +1255,8 @@ class PyClassScope(ClassScope):
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0):
if type is unspecified_type:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
......@@ -1321,6 +1343,8 @@ class CClassScope(ClassScope):
"Non-generic Python attribute cannot be exposed for writing from Python")
return entry
else:
if type is unspecified_type:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
......@@ -1477,7 +1501,12 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
}
if (PyObject_TypeCheck(method, methoddescr_type)) { /* cdef classes */
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
return PyDescr_NewClassMethod(descr->d_type, descr->d_method);
#if PY_VERSION_HEX < 0x03020000
PyTypeObject *d_type = descr->d_type;
#else
PyTypeObject *d_type = descr->d_common.d_type;
#endif
return PyDescr_NewClassMethod(d_type, descr->d_method);
}
else if (PyMethod_Check(method)) { /* python classes */
return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
......@@ -1485,7 +1514,9 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
else if (PyCFunction_Check(method)) {
return PyClassMethod_New(method);
}
PyErr_Format(PyExc_TypeError, "Class-level classmethod() can only be called on a method_descriptor or instance method.");
PyErr_Format(PyExc_TypeError,
"Class-level classmethod() can only be called on"
"a method_descriptor or instance method.");
return NULL;
}
""")
import ExprNodes
from PyrexTypes import py_object_type, unspecified_type, spanning_type
from Visitor import CythonTransform
try:
set
except NameError:
# Python 2.3
from sets import Set as set
class TypedExprNode(ExprNodes.ExprNode):
# Used for declaring assignments of a specified type whithout a known entry.
def __init__(self, type):
self.type = type
object_expr = TypedExprNode(py_object_type)
class MarkAssignments(CythonTransform):
def mark_assignment(self, lhs, rhs):
if isinstance(lhs, ExprNodes.NameNode):
if lhs.entry is None:
# TODO: This shouldn't happen...
# It looks like comprehension loop targets are not declared soon enough.
return
lhs.entry.assignments.append(rhs)
elif isinstance(lhs, ExprNodes.SequenceNode):
for arg in lhs.args:
self.mark_assignment(arg, object_expr)
else:
# Could use this info to infer cdef class attributes...
pass
def visit_SingleAssignmentNode(self, node):
self.mark_assignment(node.lhs, node.rhs)
self.visitchildren(node)
return node
def visit_CascadedAssignmentNode(self, node):
for lhs in node.lhs_list:
self.mark_assignment(lhs, node.rhs)
self.visitchildren(node)
return node
def visit_InPlaceAssignmentNode(self, node):
self.mark_assignment(node.lhs, node.create_binop_node())
self.visitchildren(node)
return node
def visit_ForInStatNode(self, node):
# TODO: Remove redundancy with range optimization...
is_range = False
sequence = node.iterator.sequence
if isinstance(sequence, ExprNodes.SimpleCallNode):
function = sequence.function
if sequence.self is None and \
isinstance(function, ExprNodes.NameNode) and \
function.name in ('range', 'xrange'):
is_range = True
self.mark_assignment(node.target, sequence.args[0])
if len(sequence.args) > 1:
self.mark_assignment(node.target, sequence.args[1])
if len(sequence.args) > 2:
self.mark_assignment(node.target,
ExprNodes.binop_node(node.pos,
'+',
sequence.args[0],
sequence.args[2]))
if not is_range:
self.mark_assignment(node.target, object_expr)
self.visitchildren(node)
return node
def visit_ForFromStatNode(self, node):
self.mark_assignment(node.target, node.bound1)
if node.step is not None:
self.mark_assignment(node.target,
ExprNodes.binop_node(node.pos,
'+',
node.bound1,
node.step))
self.visitchildren(node)
return node
def visit_ExceptClauseNode(self, node):
if node.target is not None:
self.mark_assignment(node.target, object_expr)
self.visitchildren(node)
return node
def visit_FromCImportStatNode(self, node):
pass # Can't be assigned to...
def visit_FromImportStatNode(self, node):
for name, target in node.items:
if name != "*":
self.mark_assignment(target, object_expr)
self.visitchildren(node)
return node
class PyObjectTypeInferer:
"""
If it's not declared, it's a PyObject.
"""
def infer_types(self, scope):
"""
Given a dict of entries, map all unspecified types to a specified type.
"""
for name, entry in scope.entries.items():
if entry.type is unspecified_type:
entry.type = py_object_type
class SimpleAssignmentTypeInferer:
"""
Very basic type inference.
"""
# TODO: Implement a real type inference algorithm.
# (Something more powerful than just extending this one...)
def infer_types(self, scope):
dependancies_by_entry = {} # entry -> dependancies
entries_by_dependancy = {} # dependancy -> entries
ready_to_infer = []
for name, entry in scope.entries.items():
if entry.type is unspecified_type:
all = set()
for expr in entry.assignments:
all.update(expr.type_dependencies(scope))
if all:
dependancies_by_entry[entry] = all
for dep in all:
if dep not in entries_by_dependancy:
entries_by_dependancy[dep] = set([entry])
else:
entries_by_dependancy[dep].add(entry)
else:
ready_to_infer.append(entry)
def resolve_dependancy(dep):
if dep in entries_by_dependancy:
for entry in entries_by_dependancy[dep]:
entry_deps = dependancies_by_entry[entry]
entry_deps.remove(dep)
if not entry_deps and entry != dep:
del dependancies_by_entry[entry]
ready_to_infer.append(entry)
# Try to infer things in order...
while True:
while ready_to_infer:
entry = ready_to_infer.pop()
types = [expr.infer_type(scope) for expr in entry.assignments]
if types:
entry.type = reduce(spanning_type, types)
else:
# List comprehension?
# print "No assignments", entry.pos, entry
entry.type = py_object_type
resolve_dependancy(entry)
# Deal with simple circular dependancies...
for entry, deps in dependancies_by_entry.items():
if len(deps) == 1 and deps == set([entry]):
types = [expr.infer_type(scope) for expr in entry.assignments if expr.type_dependencies(scope) == ()]
if types:
entry.type = reduce(spanning_type, types)
types = [expr.infer_type(scope) for expr in entry.assignments]
entry.type = reduce(spanning_type, types) # might be wider...
resolve_dependancy(entry)
del dependancies_by_entry[entry]
if ready_to_infer:
break
if not ready_to_infer:
break
# We can't figure out the rest with this algorithm, let them be objects.
for entry in dependancies_by_entry:
entry.type = py_object_type
def get_type_inferer():
return SimpleAssignmentTypeInferer()
......@@ -10,6 +10,7 @@ from Nodes import Node
from ExprNodes import AtomicExprNode
class TempHandle(object):
# THIS IS DEPRECATED, USE LetRefNode instead
temp = None
needs_xdecref = False
def __init__(self, type):
......@@ -23,6 +24,7 @@ class TempHandle(object):
return CleanupTempRefNode(pos, handle=self, type=self.type)
class TempRefNode(AtomicExprNode):
# THIS IS DEPRECATED, USE LetRefNode instead
# handle TempHandle
def analyse_types(self, env):
......@@ -52,6 +54,7 @@ class TempRefNode(AtomicExprNode):
rhs.free_temps(code)
class CleanupTempRefNode(TempRefNode):
# THIS IS DEPRECATED, USE LetRefNode instead
# handle TempHandle
def generate_assignment_code(self, rhs, code):
......@@ -63,6 +66,8 @@ class CleanupTempRefNode(TempRefNode):
self.handle.needs_cleanup = False
class TempsBlockNode(Node):
# THIS IS DEPRECATED, USE LetNode instead
"""
Creates a block which allocates temporary variables.
This is used by transforms to output constructs that need
......
......@@ -17,7 +17,7 @@
DEF _buffer_format_string_len = 255
cimport python_buffer as pybuf
from python_object cimport PyObject
from python_ref cimport PyObject, Py_INCREF, Py_XDECREF
cimport stdlib
cimport stdio
......@@ -151,6 +151,7 @@ cdef extern from "numpy/arrayobject.h":
npy_intp *shape "dimensions"
npy_intp *strides
dtype descr
PyObject* base
# Note: This syntax (function definition in pxd files) is an
# experimental exception made for __getbuffer__ and __releasebuffer__
......@@ -292,12 +293,6 @@ cdef extern from "numpy/arrayobject.h":
ctypedef long double npy_float96
ctypedef long double npy_float128
ctypedef float complex npy_complex64
ctypedef double complex npy_complex128
ctypedef long double complex npy_complex120
ctypedef long double complex npy_complex192
ctypedef long double complex npy_complex256
ctypedef struct npy_cfloat:
double real
double imag
......@@ -310,6 +305,26 @@ cdef extern from "numpy/arrayobject.h":
double real
double imag
ctypedef struct npy_complex64:
double real
double imag
ctypedef struct npy_complex128:
double real
double imag
ctypedef struct npy_complex160:
double real
double imag
ctypedef struct npy_complex192:
double real
double imag
ctypedef struct npy_complex256:
double real
double imag
ctypedef struct PyArray_Dims:
npy_intp *ptr
int len
......@@ -469,6 +484,13 @@ cdef extern from "numpy/arrayobject.h":
object PyArray_Take(ndarray ap, object items, int axis)
object PyArray_Put(ndarray ap, object items, object values)
void PyArray_ITER_RESET(flatiter it) nogil
void PyArray_ITER_NEXT(flatiter it) nogil
void PyArray_ITER_GOTO(flatiter it, npy_intp* destination) nogil
void PyArray_ITER_GOTO1D(flatiter it, npy_intp ind) nogil
void* PyArray_ITER_DATA(flatiter it) nogil
bint PyArray_ITER_NOTDONE(flatiter it) nogil
void PyArray_MultiIter_RESET(broadcast multi) nogil
void PyArray_MultiIter_NEXT(broadcast multi) nogil
void PyArray_MultiIter_GOTO(broadcast multi, npy_intp dest) nogil
......@@ -895,6 +917,21 @@ cdef extern from "numpy/ufuncobject.h":
(PyUFuncGenericFunction *, void **, char *, int, int, int,
int, char *, char *, int, char *)
void import_ufunc()
void import_ufunc()
cdef inline void set_array_base(ndarray arr, object base):
cdef PyObject* baseptr
if base is None:
baseptr = NULL
else:
Py_INCREF(base) # important to do this before decref below!
baseptr = <PyObject*>base
Py_XDECREF(arr.base)
arr.base = baseptr
cdef inline object get_array_base(ndarray arr):
if arr.base is NULL:
return None
else:
return <object>arr.base
......@@ -125,6 +125,7 @@ from python_mem cimport *
from python_tuple cimport *
from python_list cimport *
from python_object cimport *
from python_cobject cimport *
from python_sequence cimport *
from python_mapping cimport *
from python_iterator cimport *
......
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.2.2 Boolean Objects
......
# Please see the Python header files (object.h) for docs
# Please see the Python header files (object.h/abstract.h) for docs
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef struct bufferinfo:
void *buf
Py_ssize_t len
Py_ssize_t itemsize
int readonly
int ndim
char *format
Py_ssize_t *shape
Py_ssize_t *strides
Py_ssize_t *suboffsets
void *internal
ctypedef bufferinfo Py_buffer
cdef enum:
PyBUF_SIMPLE,
......@@ -39,23 +25,85 @@ cdef extern from "Python.h":
PyBUF_WRITE,
PyBUF_SHADOW
int PyObject_CheckBuffer(PyObject* obj)
int PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags)
void PyObject_ReleaseBuffer(PyObject *obj, Py_buffer *view)
bint PyObject_CheckBuffer(object obj)
# Return 1 if obj supports the buffer interface otherwise 0.
int PyObject_GetBuffer(object obj, Py_buffer *view, int flags) except -1
# Export obj into a Py_buffer, view. These arguments must never be
# NULL. The flags argument is a bit field indicating what kind of
# buffer the caller is prepared to deal with and therefore what
# kind of buffer the exporter is allowed to return. The buffer
# interface allows for complicated memory sharing possibilities,
# but some caller may not be able to handle all the complexity but
# may want to see if the exporter will let them take a simpler
# view to its memory.
# Some exporters may not be able to share memory in every possible
# way and may need to raise errors to signal to some consumers
# that something is just not possible. These errors should be a
# BufferError unless there is another error that is actually
# causing the problem. The exporter can use flags information to
# simplify how much of the Py_buffer structure is filled in with
# non-default values and/or raise an error if the object can’t
# support a simpler view of its memory.
# 0 is returned on success and -1 on error.
void PyBuffer_Release(object obj, object view)
# Release the buffer view over obj. This should be called when the
# buffer is no longer being used as it may free memory from it.
void* PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices)
# ??
int PyBuffer_SizeFromFormat(char *) # actually const char
# Return the implied ~Py_buffer.itemsize from the struct-stype
# ~Py_buffer.format
int PyBuffer_ToContiguous(void *buf, Py_buffer *view, Py_ssize_t len, char fort)
# ??
int PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
int PyObject_CopyData(PyObject *dest, PyObject *src)
int PyBuffer_IsContiguous(Py_buffer *view, char fort)
# ??
int PyObject_CopyToObject(object obj, void *buf, Py_ssize_t len, char fortran) except -1
# Copy len bytes of data pointed to by the contiguous chunk of
# memory pointed to by buf into the buffer exported by obj. The
# buffer must of course be writable. Return 0 on success and
# return -1 and raise an error on failure. If the object does not
# have a writable buffer, then an error is raised. If fortran is
# 'F', then if the object is multi-dimensional, then the data will
# be copied into the array in Fortran-style (first dimension
# varies the fastest). If fortran is 'C', then the data will be
# copied into the array in C-style (last dimension varies the
# fastest). If fortran is 'A', then it does not matter and the
# copy will be made in whatever way is more efficient.
int PyObject_CopyData(object dest, object src)
# Copy the data from the src buffer to the buffer of destination
bint PyBuffer_IsContiguous(Py_buffer *view, char fort)
# Return 1 if the memory defined by the view is C-style (fortran
# is 'C') or Fortran-style (fortran is 'F') contiguous or either
# one (fortran is 'A'). Return 0 otherwise.
void PyBuffer_FillContiguousStrides(int ndims,
Py_ssize_t *shape,
Py_ssize_t *strides,
int itemsize,
char fort)
# Fill the strides array with byte-strides of a contiguous
# (Fortran-style if fort is 'F' or C-style otherwise) array of the
# given shape with the given number of bytes per element.
int PyBuffer_FillInfo(Py_buffer *view, void *buf,
Py_ssize_t len, int readonly,
int flags)
int flags) except -1
# Fill in a buffer-info structure, view, correctly for an exporter
# that can only share a contiguous chunk of memory of “unsigned
# bytes” of the given length. Return 0 on success and -1 (with
# raising an error) on error.
PyObject* PyObject_Format(PyObject* obj,
PyObject *format_spec)
object PyObject_Format(object obj, object format_spec)
# Takes an arbitrary object and returns the result of calling
# obj.__format__(format_spec).
from python_ref cimport PyObject
cdef extern from "Python.h":
###########################################################################
# Warning:
#
# The CObject API is deprecated as of Python 3.1. Please switch to
# the new Capsules API.
###########################################################################
int PyCObject_Check(object p)
# Return true if its argument is a PyCObject.
object PyCObject_FromVoidPtr(void* cobj, void (*destr)(void *))
# Return value: New reference.
#
# Create a PyCObject from the void * cobj. The destr function will
# be called when the object is reclaimed, unless it is NULL.
object PyCObject_FromVoidPtrAndDesc(void* cobj, void* desc, void (*destr)(void *, void *))
# Return value: New reference.
#
# Create a PyCObject from the void * cobj. The destr function will
# be called when the object is reclaimed. The desc argument can be
# used to pass extra callback data for the destructor function.
void* PyCObject_AsVoidPtr(object self)
# Return the object void * that the PyCObject self was created with.
void* PyCObject_GetDesc(object self)
# Return the description void * that the PyCObject self was created with.
int PyCObject_SetVoidPtr(object self, void* cobj)
# Set the void pointer inside self to cobj. The PyCObject must not
# have an associated destructor. Return true on success, false on
# failure.
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef struct Py_complex
############################################################################
......
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.4.1 Dictionary Objects
############################################################################
# PyDictObject
# This subtype of PyObject represents a Python dictionary object.
#
# This subtype of PyObject represents a Python dictionary object
# (i.e. the 'dict' type).
# PyTypeObject PyDict_Type
# This instance of PyTypeObject represents the Python dictionary type. This is exposed to Python programs as dict and types.DictType.
#
# This instance of PyTypeObject represents the Python dictionary
# type. This is exposed to Python programs as dict and
# types.DictType.
bint PyDict_Check(object p)
# Return true if p is a dict object or an instance of a subtype of
......@@ -29,7 +38,7 @@ cdef extern from "Python.h":
void PyDict_Clear(object p)
# Empty an existing dictionary of all key-value pairs.
int PyDict_Contains(object p, object key)
int PyDict_Contains(object p, object key) except -1
# Determine if dictionary p contains key. If an item in p is
# matches key, return 1, otherwise return 0. On error, return
# -1. This is equivalent to the Python expression "key in p".
......@@ -38,22 +47,22 @@ cdef extern from "Python.h":
# Return value: New reference.
# Return a new dictionary that contains the same key-value pairs as p.
int PyDict_SetItem(object p, object key, object val)
int PyDict_SetItem(object p, object key, object val) except -1
# Insert value into the dictionary p with a key of key. key must
# be hashable; if it isn't, TypeError will be raised. Return 0 on
# success or -1 on failure.
int PyDict_SetItemString(object p, char *key, object val)
int PyDict_SetItemString(object p, char *key, object val) except -1
# Insert value into the dictionary p using key as a key. key
# should be a char*. The key object is created using
# PyString_FromString(key). Return 0 on success or -1 on failure.
int PyDict_DelItem(object p, object key)
int PyDict_DelItem(object p, object key) except -1
# Remove the entry in dictionary p with key key. key must be
# hashable; if it isn't, TypeError is raised. Return 0 on success
# or -1 on failure.
int PyDict_DelItemString(object p, char *key)
int PyDict_DelItemString(object p, char *key) except -1
# Remove the entry in dictionary p which has a key specified by
# the string key. Return 0 on success or -1 on failure.
......@@ -87,7 +96,8 @@ cdef extern from "Python.h":
# Python Library Reference).
Py_ssize_t PyDict_Size(object p)
# Return the number of items in the dictionary. This is equivalent to "len(p)" on a dictionary.
# Return the number of items in the dictionary. This is equivalent
# to "len(p)" on a dictionary.
int PyDict_Next(object p, Py_ssize_t *ppos, PyObject* *pkey, PyObject* *pvalue)
# Iterate over all key-value pairs in the dictionary p. The int
......@@ -128,7 +138,7 @@ cdef extern from "Python.h":
# Py_DECREF(o);
# }
int PyDict_Merge(object a, object b, int override)
int PyDict_Merge(object a, object b, int override) except -1
# Iterate over mapping object b adding key-value pairs to
# dictionary a. b may be a dictionary, or any object supporting
# PyMapping_Keys() and PyObject_GetItem(). If override is true,
......@@ -137,11 +147,11 @@ cdef extern from "Python.h":
# matching key in a. Return 0 on success or -1 if an exception was
# raised.
int PyDict_Update(object a, object b)
int PyDict_Update(object a, object b) except -1
# This is the same as PyDict_Merge(a, b, 1) in C, or a.update(b)
# in Python. Return 0 on success or -1 if an exception was raised.
int PyDict_MergeFromSeq2(object a, object seq2, int override)
int PyDict_MergeFromSeq2(object a, object seq2, int override) except -1
# Update or merge into dictionary a, from the key-value pairs in
# seq2. seq2 must be an iterable object producing iterable objects
# of length 2, viewed as key-value pairs. In case of duplicate
......
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
#####################################################################
# 3. Exception Handling
......
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.2.3
############################################################################
# PyFloatObject
#
# This subtype of PyObject represents a Python floating point object.
# PyTypeObject PyFloat_Type
# This instance of PyTypeObject represents the Python floating point type. This is the same object as float and types.FloatType.
#
# This instance of PyTypeObject represents the Python floating
# point type. This is the same object as float and
# types.FloatType.
bint PyFloat_Check(object p)
# Return true if its argument is a PyFloatObject or a subtype of
......@@ -31,4 +35,5 @@ cdef extern from "Python.h":
# Return a C double representation of the contents of pyfloat.
double PyFloat_AS_DOUBLE(object pyfloat)
# Return a C double representation of the contents of pyfloat, but without error checking.
# Return a C double representation of the contents of pyfloat, but
# without error checking.
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.5.3 Function Objects
############################################################################
# There are a few functions specific to Python functions.
# PyFunctionObject
#
# The C structure used for functions.
# PyTypeObject PyFunction_Type
#
# This is an instance of PyTypeObject and represents the Python
# function type. It is exposed to Python programmers as
# types.FunctionType.
......@@ -43,7 +49,7 @@ cdef extern from "Python.h":
# Return the argument default values of the function object
# op. This can be a tuple of arguments or NULL.
int PyFunction_SetDefaults(object op, object defaults)
int PyFunction_SetDefaults(object op, object defaults) except -1
# Set the argument default values for the function object
# op. defaults must be Py_None or a tuple.
# Raises SystemError and returns -1 on failure.
......@@ -53,7 +59,7 @@ cdef extern from "Python.h":
# Return the closure associated with the function object op. This
# can be NULL or a tuple of cell objects.
int PyFunction_SetClosure(object op, object closure)
int PyFunction_SetClosure(object op, object closure) except -1
# Set the closure associated with the function object op. closure
# must be Py_None or a tuple of cell objects.
# Raises SystemError and returns -1 on failure.
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.5.2 Instance Objects
############################################################################
# PyTypeObject PyInstance_Type
#
# Type object for class instances.
# int PyInstance_Check(PyObject *obj)
int PyInstance_Check(object obj)
# Return true if obj is an instance.
object PyInstance_New(PyObject* cls, object arg, object kw)
object PyInstance_New(object cls, object arg, object kw)
# Return value: New reference.
# Create a new instance of a specific class. The parameters arg
# and kw are used as the positional and keyword parameters to the
......
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef unsigned long long PY_LONG_LONG
############################################################################
# Integer Objects
......@@ -48,7 +48,7 @@ cdef extern from "Python.h":
# Create a new integer object with a value of ival. If the value
# exceeds LONG_MAX, a long integer object is returned.
long PyInt_AsLong(object io)
long PyInt_AsLong(object io) except? -1
# Will first attempt to cast the object to a PyIntObject, if it is
# not already one, and then return its value. If there is an
# error, -1 is returned, and the caller should check
......@@ -64,7 +64,6 @@ cdef extern from "Python.h":
# value as unsigned long. This function does not check for
# overflow.
ctypedef unsigned long long PY_LONG_LONG
PY_LONG_LONG PyInt_AsUnsignedLongLongMask(object io)
# Will first attempt to cast the object to a PyIntObject or
# PyLongObject, if it is not already one, and then return its
......
......@@ -3,7 +3,7 @@ cdef extern from "Python.h":
############################################################################
# 6.5 Iterator Protocol
############################################################################
int PyIter_Check(object o)
bint PyIter_Check(object o)
# Return true if the object o supports the iterator protocol.
object PyIter_Next(object o)
......
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# Lists
############################################################################
object PyList_New(Py_ssize_t len)
# Return a new list of length len on success, or NULL on
# failure. Note: If length is greater than zero, the returned list
# object's items are set to NULL. Thus you cannot use abstract API
# Return a new list of length len on success, or NULL on failure.
#
# Note: If length is greater than zero, the returned list object's
# items are set to NULL. Thus you cannot use abstract API
# functions such as PySequence_SetItem() or expose the object to
# Python code before setting all items to a real object with
# PyList_SetItem().
bint PyList_Check(object p)
# Return true if p is a list object or an instance of a subtype of the list type.
# Return true if p is a list object or an instance of a subtype of
# the list type.
bint PyList_CheckExact(object p)
# Return true if p is a list object, but not an instance of a subtype of the list type.
# Return true if p is a list object, but not an instance of a
# subtype of the list type.
Py_ssize_t PyList_Size(object list)
# Return the length of the list object in list; this is equivalent to "len(list)" on a list object.
# Return the length of the list object in list; this is equivalent
# to "len(list)" on a list object.
Py_ssize_t PyList_GET_SIZE(object list)
# Macro form of PyList_Size() without error checking.
......@@ -35,7 +40,7 @@ cdef extern from "Python.h":
# Return value: Borrowed reference.
# Macro form of PyList_GetItem() without error checking.
int PyList_SetItem(object list, Py_ssize_t index, object item)
int PyList_SetItem(object list, Py_ssize_t index, object item) except -1
# Set the item at index index in list to item. Return 0 on success
# or -1 on failure. Note: This function ``steals'' a reference to
# item and discards a reference to an item already in the list at
......@@ -49,12 +54,12 @@ cdef extern from "Python.h":
# to any item that it being replaced; any reference in list at
# position i will be *leaked*.
int PyList_Insert(object list, Py_ssize_t index, object item)
int PyList_Insert(object list, Py_ssize_t index, object item) except -1
# Insert the item item into list list in front of index
# index. Return 0 if successful; return -1 and set an exception if
# unsuccessful. Analogous to list.insert(index, item).
int PyList_Append(object list, object item)
int PyList_Append(object list, object item) except -1
# Append the object item at the end of list list. Return 0 if
# successful; return -1 and set an exception if
# unsuccessful. Analogous to list.append(item).
......@@ -65,17 +70,17 @@ cdef extern from "Python.h":
# between low and high. Return NULL and set an exception if
# unsuccessful. Analogous to list[low:high].
int PyList_SetSlice(object list, Py_ssize_t low, Py_ssize_t high, object itemlist)
int PyList_SetSlice(object list, Py_ssize_t low, Py_ssize_t high, object itemlist) except -1
# Set the slice of list between low and high to the contents of
# itemlist. Analogous to list[low:high] = itemlist. The itemlist
# may be NULL, indicating the assignment of an empty list (slice
# deletion). Return 0 on success, -1 on failure.
int PyList_Sort(object list)
int PyList_Sort(object list) except -1
# Sort the items of list in place. Return 0 on success, -1 on
# failure. This is equivalent to "list.sort()".
int PyList_Reverse(object list)
int PyList_Reverse(object list) except -1
# Reverse the items of list in place. Return 0 on success, -1 on
# failure. This is the equivalent of "list.reverse()".
......
from python_unicode cimport Py_UNICODE
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef long PY_LONG_LONG
ctypedef long long PY_LONG_LONG
ctypedef unsigned long long uPY_LONG_LONG
############################################################################
# 7.2.3 Long Integer Objects
############################################################################
# PyLongObject
#
# This subtype of PyObject represents a Python long integer object.
# PyTypeObject PyLong_Type
#
# This instance of PyTypeObject represents the Python long integer
# type. This is the same object as long and types.LongType.
......@@ -29,8 +35,7 @@ cdef extern from "Python.h":
# Return value: New reference.
# Return a new PyLongObject object from a C long long, or NULL on failure.
object PyLong_FromUnsignedLongLong(PY_LONG_LONG v)
#PyObject* PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG v)
object PyLong_FromUnsignedLongLong(uPY_LONG_LONG v)
# Return value: New reference.
# Return a new PyLongObject object from a C unsigned long long, or NULL on failure.
......@@ -51,8 +56,7 @@ cdef extern from "Python.h":
# inclusive. Leading spaces are ignored. If there are no digits,
# ValueError will be raised.
# object PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base)
object PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base)
# Return value: New reference.
# Convert a sequence of Unicode digits to a Python long integer
# value. The first parameter, u, points to the first character of
......@@ -82,7 +86,7 @@ cdef extern from "Python.h":
# cannot be represented as a long long, an OverflowError will be
# raised.
PY_LONG_LONG PyLong_AsUnsignedLongLong(object pylong)
uPY_LONG_LONG PyLong_AsUnsignedLongLong(object pylong)
#unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong(object pylong)
# Return a C unsigned long long from a Python long integer. If
# pylong cannot be represented as an unsigned long long, an
......@@ -93,13 +97,12 @@ cdef extern from "Python.h":
# Return a C unsigned long from a Python long integer, without
# checking for overflow.
PY_LONG_LONG PyLong_AsUnsignedLongLongMask(object io)
uPY_LONG_LONG PyLong_AsUnsignedLongLongMask(object io)
#unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(object io)
# Return a C unsigned long long from a Python long integer,
# without checking for overflow.
double PyLong_AsDouble(object pylong)
double PyLong_AsDouble(object pylong) except? -1.0
# Return a C double representation of the contents of pylong. If
# pylong cannot be approximately represented as a double, an
# OverflowError exception is raised and -1.0 will be returned.
......
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 6.4 Mapping Protocol
......@@ -9,17 +8,17 @@ cdef extern from "Python.h":
# Return 1 if the object provides mapping protocol, and 0
# otherwise. This function always succeeds.
Py_ssize_t PyMapping_Length(object o)
Py_ssize_t PyMapping_Length(object o) except -1
# Returns the number of keys in object o on success, and -1 on
# failure. For objects that do not provide mapping protocol, this
# is equivalent to the Python expression "len(o)".
int PyMapping_DelItemString(object o, char *key)
int PyMapping_DelItemString(object o, char *key) except -1
# Remove the mapping for object key from the object o. Return -1
# on failure. This is equivalent to the Python statement "del
# o[key]".
int PyMapping_DelItem(object o, object key)
int PyMapping_DelItem(object o, object key) except -1
# Remove the mapping for object key from the object o. Return -1
# on failure. This is equivalent to the Python statement "del
# o[key]".
......@@ -58,7 +57,7 @@ cdef extern from "Python.h":
# failure. This is the equivalent of the Python expression
# "o[key]".
int PyMapping_SetItemString(object o, char *key, object v)
int PyMapping_SetItemString(object o, char *key, object v) except -1
# Map the object key to the value v in object o. Returns -1 on
# failure. This is the equivalent of the Python statement "o[key]
# = v".
......
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef struct _inittab
#####################################################################
......@@ -50,7 +51,7 @@ cdef extern from "Python.h":
# the reloaded module, or NULL with an exception set on failure
# (the module still exists in this case).
PyObject* PyImport_AddModule(char *name)
PyObject* PyImport_AddModule(char *name) except NULL
# Return value: Borrowed reference.
# Return the module object corresponding to a module name. The
# name argument may be of the form package.module. First check the
......@@ -96,7 +97,7 @@ cdef extern from "Python.h":
# variable.
int PyImport_ImportFrozenModule(char *name)
int PyImport_ImportFrozenModule(char *name) except -1
# Load a frozen module named name. Return 1 for success, 0 if the
# module is not found, and -1 with an exception set if the
# initialization failed. To access the imported module on a
......@@ -105,7 +106,7 @@ cdef extern from "Python.h":
# imported.)
int PyImport_ExtendInittab(_inittab *newtab)
int PyImport_ExtendInittab(_inittab *newtab) except -1
# Add a collection of modules to the table of built-in
# modules. The newtab array must end with a sentinel entry which
# contains NULL for the name field; failure to provide the
......@@ -118,7 +119,9 @@ cdef extern from "Python.h":
#####################################################################
# 7.5.5 Module Objects
#####################################################################
# PyTypeObject PyModule_Type
#
# This instance of PyTypeObject represents the Python module
# type. This is exposed to Python programs as types.ModuleType.
......@@ -129,7 +132,7 @@ cdef extern from "Python.h":
bint PyModule_CheckExact(object p)
# Return true if p is a module object, but not a subtype of PyModule_Type.
object PyModule_New( char *name)
object PyModule_New(char *name)
# Return value: New reference.
# Return a new module object with the __name__ attribute set to
# name. Only the module's __doc__ and __name__ attributes are
......@@ -144,28 +147,28 @@ cdef extern from "Python.h":
# use other PyModule_*() and PyObject_*() functions rather than
# directly manipulate a module's __dict__.
char* PyModule_GetName(object module)
char* PyModule_GetName(object module) except NULL
# Return module's __name__ value. If the module does not provide
# one, or if it is not a string, SystemError is raised and NULL is
# returned.
char* PyModule_GetFilename(object module)
char* PyModule_GetFilename(object module) except NULL
# Return the name of the file from which module was loaded using
# module's __file__ attribute. If this is not defined, or if it is
# not a string, raise SystemError and return NULL.
int PyModule_AddObject(object module, char *name, object value)
int PyModule_AddObject(object module, char *name, object value) except -1
# Add an object to module as name. This is a convenience function
# which can be used from the module's initialization
# function. This steals a reference to value. Return -1 on error,
# 0 on success.
int PyModule_AddIntant(object module, char *name, long value)
int PyModule_AddIntant(object module, char *name, long value) except -1
# Add an integer ant to module as name. This convenience
# function can be used from the module's initialization
# function. Return -1 on error, 0 on success.
int PyModule_AddStringant(object module, char *name, char *value)
int PyModule_AddStringant(object module, char *name, char *value) except -1
# Add a string constant to module as name. This convenience
# function can be used from the module's initialization
# function. The string value must be null-terminated. Return -1 on
......
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef void PyTypeObject
ctypedef struct FILE
from python_ref cimport PyObject
cdef extern from "Python.h":
#####################################################################
# 6.2 Number Protocol
......@@ -203,7 +201,7 @@ cdef extern from "Python.h":
# failure. The operation is done in-place when o1 supports
# it. This is the equivalent of the Python statement "o1 |= o2".
int PyNumber_Coerce(PyObject **p1, PyObject **p2)
int PyNumber_Coerce(PyObject **p1, PyObject **p2) except -1
# This function takes the addresses of two variables of type
# PyObject*. If the objects pointed to by *p1 and *p2 have the
# same type, increment their reference count and return 0
......@@ -249,4 +247,5 @@ cdef extern from "Python.h":
# integer or PY_SSIZE_T_MAX for a positive integer.
bint PyIndex_Check(object o)
# Returns True if o is an index integer (has the nb_index slot of the tp_as_number structure filled in).
# Returns True if o is an index integer (has the nb_index slot of
# the tp_as_number structure filled in).
from python_ref cimport PyObject, PyTypeObject
from stdio cimport FILE
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef void PyTypeObject
ctypedef struct FILE
#####################################################################
# 6.1 Object Protocol
#####################################################################
int PyObject_Print(object o, FILE *fp, int flags)
int PyObject_Print(object o, FILE *fp, int flags) except -1
# Print an object o, on file fp. Returns -1 on error. The flags
# argument is used to enable certain printing options. The only
# option currently supported is Py_PRINT_RAW; if given, the str()
......@@ -34,22 +34,22 @@ cdef extern from "Python.h":
# or NULL on failure. This is the equivalent of the Python
# expression "o.attr_name".
int PyObject_SetAttrString(object o, char *attr_name, object v)
int PyObject_SetAttrString(object o, char *attr_name, object v) except -1
# Set the value of the attribute named attr_name, for object o, to
# the value v. Returns -1 on failure. This is the equivalent of
# the Python statement "o.attr_name = v".
int PyObject_SetAttr(object o, object attr_name, object v)
int PyObject_SetAttr(object o, object attr_name, object v) except -1
# Set the value of the attribute named attr_name, for object o, to
# the value v. Returns -1 on failure. This is the equivalent of
# the Python statement "o.attr_name = v".
int PyObject_DelAttrString(object o, char *attr_name)
int PyObject_DelAttrString(object o, char *attr_name) except -1
# Delete attribute named attr_name, for object o. Returns -1 on
# failure. This is the equivalent of the Python statement: "del
# o.attr_name".
int PyObject_DelAttr(object o, object attr_name)
int PyObject_DelAttr(object o, object attr_name) except -1
# Delete attribute named attr_name, for object o. Returns -1 on
# failure. This is the equivalent of the Python statement "del
# o.attr_name".
......@@ -64,7 +64,7 @@ cdef extern from "Python.h":
# opid. Returns the value of the comparison on success, or NULL on
# failure.
int PyObject_RichCompareBool(object o1, object o2, int opid)
bint PyObject_RichCompareBool(object o1, object o2, int opid) except -1
# Compare the values of o1 and o2 using the operation specified by
# opid, which must be one of Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, or
# Py_GE, corresponding to <, <=, ==, !=, >, or >=
......@@ -72,14 +72,14 @@ cdef extern from "Python.h":
# otherwise. This is the equivalent of the Python expression "o1
# op o2", where op is the operator corresponding to opid.
int PyObject_Cmp(object o1, object o2, int *result)
int PyObject_Cmp(object o1, object o2, int *result) except -1
# Compare the values of o1 and o2 using a routine provided by o1,
# if one exists, otherwise with a routine provided by o2. The
# result of the comparison is returned in result. Returns -1 on
# failure. This is the equivalent of the Python statement "result
# = cmp(o1, o2)".
int PyObject_Compare(object o1, object o2)
int PyObject_Compare(object o1, object o2) except *
# Compare the values of o1 and o2 using a routine provided by o1,
# if one exists, otherwise with a routine provided by o2. Returns
# the result of the comparison on success. On error, the value
......@@ -108,7 +108,7 @@ cdef extern from "Python.h":
# is the equivalent of the Python expression "unicode(o)". Called
# by the unicode() built-in function.
bint PyObject_IsInstance(object inst, object cls)
bint PyObject_IsInstance(object inst, object cls) except -1
# Returns 1 if inst is an instance of the class cls or a subclass
# of cls, or 0 if not. On error, returns -1 and sets an
# exception. If cls is a type object rather than a class object,
......@@ -133,7 +133,7 @@ cdef extern from "Python.h":
# fashion for A -- the presence of the __bases__ attribute is
# considered sufficient for this determination.
bint PyObject_IsSubclass(object derived, object cls)
bint PyObject_IsSubclass(object derived, object cls) except -1
# Returns 1 if the class derived is identical to or derived from
# the class cls, otherwise returns 0. In case of an error, returns
# -1. If cls is a tuple, the check will be done against every
......@@ -207,17 +207,17 @@ cdef extern from "Python.h":
# NULL. Returns the result of the call on success, or NULL on
# failure.
long PyObject_Hash(object o)
long PyObject_Hash(object o) except? -1
# Compute and return the hash value of an object o. On failure,
# return -1. This is the equivalent of the Python expression
# "hash(o)".
bint PyObject_IsTrue(object o)
bint PyObject_IsTrue(object o) except -1
# Returns 1 if the object o is considered to be true, and 0
# otherwise. This is equivalent to the Python expression "not not
# o". On failure, return -1.
bint PyObject_Not(object o)
bint PyObject_Not(object o) except -1
# Returns 0 if the object o is considered to be true, and 1
# otherwise. This is equivalent to the Python expression "not
# o". On failure, return -1.
......@@ -237,8 +237,8 @@ cdef extern from "Python.h":
# Return true if the object o is of type type or a subtype of
# type. Both parameters must be non-NULL.
Py_ssize_t PyObject_Length(object o)
Py_ssize_t PyObject_Size(object o)
Py_ssize_t PyObject_Length(object o) except -1
Py_ssize_t PyObject_Size(object o) except -1
# Return the length of object o. If the object o provides either
# the sequence and mapping protocols, the sequence length is
# returned. On error, -1 is returned. This is the equivalent to
......@@ -250,15 +250,15 @@ cdef extern from "Python.h":
# failure. This is the equivalent of the Python expression
# "o[key]".
int PyObject_SetItem(object o, object key, object v)
int PyObject_SetItem(object o, object key, object v) except -1
# Map the object key to the value v. Returns -1 on failure. This
# is the equivalent of the Python statement "o[key] = v".
int PyObject_DelItem(object o, object key)
int PyObject_DelItem(object o, object key) except -1
# Delete the mapping for key from o. Returns -1 on failure. This
# is the equivalent of the Python statement "del o[key]".
int PyObject_AsFileDescriptor(object o)
int PyObject_AsFileDescriptor(object o) except -1
# Derives a file-descriptor from a Python object. If the object is
# an integer or long integer, its value is returned. If not, the
# object's fileno() method is called if it exists; the method must
......
from python_ref cimport PyObject
# available since Python 3.1!
# note all char* in the below functions are actually const char*
cdef extern from "Python.h":
ctypedef struct PyCapsule_Type
# This subtype of PyObject represents an opaque value, useful for
# C extension modules who need to pass an opaque value (as a void*
# pointer) through Python code to other C code. It is often used
# to make a C function pointer defined in one module available to
# other modules, so the regular import mechanism can be used to
# access C APIs defined in dynamically loaded modules.
ctypedef void (*PyCapsule_Destructor)(object o)
# The type of a destructor callback for a capsule.
#
# See PyCapsule_New() for the semantics of PyCapsule_Destructor
# callbacks.
bint PyCapsule_CheckExact(object o)
# Return true if its argument is a PyCapsule.
object PyCapsule_New(void *pointer, char *name,
PyCapsule_Destructor destructor)
# Return value: New reference.
#
# Create a PyCapsule encapsulating the pointer. The pointer
# argument may not be NULL.
#
# On failure, set an exception and return NULL.
#
# The name string may either be NULL or a pointer to a valid C
# string. If non-NULL, this string must outlive the
# capsule. (Though it is permitted to free it inside the
# destructor.)
#
# If the destructor argument is not NULL, it will be called with
# the capsule as its argument when it is destroyed.
#
# If this capsule will be stored as an attribute of a module, the
# name should be specified as modulename.attributename. This will
# enable other modules to import the capsule using
# PyCapsule_Import().
void* PyCapsule_GetPointer(object capsule, char *name)
# Retrieve the pointer stored in the capsule. On failure, set an
# exception and return NULL.
#
# The name parameter must compare exactly to the name stored in
# the capsule. If the name stored in the capsule is NULL, the name
# passed in must also be NULL. Python uses the C function strcmp()
# to compare capsule names.
PyCapsule_Destructor PyCapsule_GetDestructor(object capsule)
# Return the current destructor stored in the capsule. On failure,
# set an exception and return NULL.
#
# It is legal for a capsule to have a NULL destructor. This makes
# a NULL return code somewhat ambiguous; use PyCapsule_IsValid()
# or PyErr_Occurred() to disambiguate.
char* PyCapsule_GetName(object capsule)
# Return the current name stored in the capsule. On failure, set
# an exception and return NULL.
#
# It is legal for a capsule to have a NULL name. This makes a NULL
# return code somewhat ambiguous; use PyCapsule_IsValid() or
# PyErr_Occurred() to disambiguate.
void* PyCapsule_GetContext(object capsule)
# Return the current context stored in the capsule. On failure,
# set an exception and return NULL.
#
# It is legal for a capsule to have a NULL context. This makes a
# NULL return code somewhat ambiguous; use PyCapsule_IsValid() or
# PyErr_Occurred() to disambiguate.
int PyCapsule_IsValid(object capsule, char *name)
# Determines whether or not capsule is a valid capsule. A valid
# capsule is non-NULL, passes PyCapsule_CheckExact(), has a
# non-NULL pointer stored in it, and its internal name matches the
# name parameter. (See PyCapsule_GetPointer() for information on
# how capsule names are compared.)
#
# In other words, if PyCapsule_IsValid() returns a true value,
# calls to any of the accessors (any function starting with
# PyCapsule_Get()) are guaranteed to succeed.
#
# Return a nonzero value if the object is valid and matches the
# name passed in. Return 0 otherwise. This function will not fail.
int PyCapsule_SetPointer(object capsule, void *pointer)
# Set the void pointer inside capsule to pointer. The pointer may
# not be NULL.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetDestructor(object capsule, PyCapsule_Destructor destructor)
# Set the destructor inside capsule to destructor.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetName(object capsule, char *name)
# Set the name inside capsule to name. If non-NULL, the name must
# outlive the capsule. If the previous name stored in the capsule
# was not NULL, no attempt is made to free it.
#
# Return 0 on success. Return nonzero and set an exception on
# failure.
int PyCapsule_SetContext(object capsule, void *context)
# Set the context pointer inside capsule to context. Return 0 on
# success. Return nonzero and set an exception on failure.
void* PyCapsule_Import(char *name, int no_block)
# Import a pointer to a C object from a capsule attribute in a
# module. The name parameter should specify the full name to the
# attribute, as in module.attribute. The name stored in the
# capsule must match this string exactly. If no_block is true,
# import the module without blocking (using
# PyImport_ImportModuleNoBlock()). If no_block is false, import
# the module conventionally (using PyImport_ImportModule()).
#
# Return the capsule’s internal pointer on success. On failure,
# set an exception and return NULL. However, if PyCapsule_Import()
# failed to import the module, and no_block was true, no exception
# is set.
cdef extern from "Python.h":
ctypedef void PyTypeObject
ctypedef struct PyTypeObject
ctypedef struct PyObject:
Py_ssize_t ob_refcnt
PyTypeObject *ob_type
ctypedef struct FILE
#####################################################################
......@@ -15,7 +14,7 @@ cdef extern from "Python.h":
# be NULL; if you aren't sure that it isn't NULL, use
# Py_XINCREF().
void Py_XINCREF(object o)
void Py_XINCREF(PyObject* o)
# Increment the reference count for object o. The object may be NULL, in which case the macro has no effect.
void Py_DECREF(object o)
......@@ -36,13 +35,13 @@ cdef extern from "Python.h":
# temporary variable, update the list data structure, and then
# call Py_DECREF() for the temporary variable.
void Py_XDECREF(object o)
void Py_XDECREF(PyObject* o)
# Decrement the reference count for object o. The object may be
# NULL, in which case the macro has no effect; otherwise the
# effect is the same as for Py_DECREF(), and the same warning
# applies.
void Py_CLEAR(object o)
void Py_CLEAR(PyObject* o)
# Decrement the reference count for object o. The object may be
# NULL, in which case the macro has no effect; otherwise the
# effect is the same as for Py_DECREF(), except that the argument
......
############################################################################
# 6.3 Sequence Protocol
############################################################################
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 6.3 Sequence Protocol
############################################################################
bint PySequence_Check(object o)
# Return 1 if the object provides sequence protocol, and 0
# otherwise. This function always succeeds.
Py_ssize_t PySequence_Size(object o)
Py_ssize_t PySequence_Size(object o) except -1
# Returns the number of objects in sequence o on success, and -1
# on failure. For objects that do not provide sequence protocol,
# this is equivalent to the Python expression "len(o)".
Py_ssize_t PySequence_Length(object o)
Py_ssize_t PySequence_Length(object o) except -1
# Alternate name for PySequence_Size().
object PySequence_Concat(object o1, object o2)
......@@ -54,37 +54,37 @@ cdef extern from "Python.h":
# on failure. This is the equivalent of the Python expression
# "o[i1:i2]".
int PySequence_SetItem(object o, Py_ssize_t i, object v)
int PySequence_SetItem(object o, Py_ssize_t i, object v) except -1
# Assign object v to the ith element of o. Returns -1 on
# failure. This is the equivalent of the Python statement "o[i] =
# v". This function does not steal a reference to v.
int PySequence_DelItem(object o, Py_ssize_t i)
int PySequence_DelItem(object o, Py_ssize_t i) except -1
# Delete the ith element of object o. Returns -1 on failure. This
# is the equivalent of the Python statement "del o[i]".
int PySequence_SetSlice(object o, Py_ssize_t i1, Py_ssize_t i2, object v)
int PySequence_SetSlice(object o, Py_ssize_t i1, Py_ssize_t i2, object v) except -1
# Assign the sequence object v to the slice in sequence object o
# from i1 to i2. This is the equivalent of the Python statement
# "o[i1:i2] = v".
int PySequence_DelSlice(object o, Py_ssize_t i1, Py_ssize_t i2)
int PySequence_DelSlice(object o, Py_ssize_t i1, Py_ssize_t i2) except -1
# Delete the slice in sequence object o from i1 to i2. Returns -1
# on failure. This is the equivalent of the Python statement "del
# o[i1:i2]".
int PySequence_Count(object o, object value)
int PySequence_Count(object o, object value) except -1
# Return the number of occurrences of value in o, that is, return
# the number of keys for which o[key] == value. On failure, return
# -1. This is equivalent to the Python expression
# "o.count(value)".
int PySequence_Contains(object o, object value)
int PySequence_Contains(object o, object value) except -1
# Determine if o contains value. If an item in o is equal to
# value, return 1, otherwise return 0. On error, return -1. This
# is equivalent to the Python expression "value in o".
int PySequence_Index(object o, object value)
int PySequence_Index(object o, object value) except -1
# Return the first index i for which o[i] == value. On error,
# return -1. This is equivalent to the Python expression
# "o.index(value)".
......
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# 7.5.14 Set Objects
......@@ -63,9 +62,11 @@ cdef extern from "Python.h":
# frozenset. Return the new set on success or NULL on
# failure. Raise TypeError if iterable is not actually iterable.
# The following functions and macros are available for instances of set or frozenset or instances of their subtypes.
int PySet_Size(object anyset)
# The following functions and macros are available for instances
# of set or frozenset or instances of their subtypes.
int PySet_Size(object anyset) except -1
# Return the length of a set or frozenset object. Equivalent to
# "len(anyset)". Raises a PyExc_SystemError if anyset is not a
# set, frozenset, or an instance of a subtype.
......@@ -73,7 +74,7 @@ cdef extern from "Python.h":
int PySet_GET_SIZE(object anyset)
# Macro form of PySet_Size() without error checking.
int PySet_Contains(object anyset, object key)
bint PySet_Contains(object anyset, object key) except -1
# Return 1 if found, 0 if not found, and -1 if an error is
# encountered. Unlike the Python __contains__() method, this
# function does not automatically convert unhashable sets into
......@@ -81,17 +82,18 @@ cdef extern from "Python.h":
# unhashable. Raise PyExc_SystemError if anyset is not a set,
# frozenset, or an instance of a subtype.
# The following functions are available for instances of set or
# its subtypes but not for instances of frozenset or its subtypes.
int PySet_Add(object set, object key)
int PySet_Add(object set, object key) except -1
# Add key to a set instance. Does not apply to frozenset
# instances. Return 0 on success or -1 on failure. Raise a
# TypeError if the key is unhashable. Raise a MemoryError if there
# is no room to grow. Raise a SystemError if set is an not an
# instance of set or its subtype.
int PySet_Discard(object set, object key)
bint PySet_Discard(object set, object key) except -1
# Return 1 if found and removed, 0 if not found (no action taken),
# and -1 if an error is encountered. Does not raise KeyError for
# missing keys. Raise a TypeError if the key is unhashable. Unlike
......@@ -100,7 +102,7 @@ cdef extern from "Python.h":
# frozensets. Raise PyExc_SystemError if set is an not an instance
# of set or its subtype.
PySet_Pop(object set)
object PySet_Pop(object set)
# Return value: New reference.
# Return a new reference to an arbitrary object in the set, and
# removes the object from the set. Return NULL on failure. Raise
......@@ -109,4 +111,3 @@ cdef extern from "Python.h":
int PySet_Clear(object set)
# Empty an existing set of all elements.
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef struct va_list
############################################################################
# 7.3.1 String Objects
############################################################################
# These functions raise TypeError when expecting a string
# parameter and are called with a non-string parameter.
# PyStringObject
......@@ -72,7 +74,7 @@ cdef extern from "Python.h":
Py_ssize_t PyString_GET_SIZE(object string)
# Macro form of PyString_Size() but without error checking.
char* PyString_AsString(object string)
char* PyString_AsString(object string) except NULL
# Return a NUL-terminated representation of the contents of
# string. The pointer refers to the internal buffer of string, not
# a copy. The data must not be modified in any way, unless the
......@@ -87,7 +89,7 @@ cdef extern from "Python.h":
# checking. Only string objects are supported; no Unicode objects
# should be passed.
int PyString_AsStringAndSize(object obj, char **buffer, Py_ssize_t *length)
int PyString_AsStringAndSize(object obj, char **buffer, Py_ssize_t *length) except -1
# Return a NULL-terminated representation of the contents of the
# object obj through the output variables buffer and length.
#
......@@ -118,7 +120,7 @@ cdef extern from "Python.h":
# newpart appended to string. This version decrements the
# reference count of newpart.
int _PyString_Resize(PyObject **string, Py_ssize_t newsize)
int _PyString_Resize(PyObject **string, Py_ssize_t newsize) except -1
# A way to resize a string object even though it is
# ``immutable''. Only use this to build up a brand new string
# object; don't use this if the string may already be known in
......
from python_ref cimport PyObject
cdef extern from "Python.h":
ctypedef void PyObject
############################################################################
# Tuples
......@@ -30,7 +31,7 @@ cdef extern from "Python.h":
# Return the size of the tuple p, which must be non-NULL and point
# to a tuple; no error checking is performed.
PyObject* PyTuple_GetItem(object p, Py_ssize_t pos)
PyObject* PyTuple_GetItem(object p, Py_ssize_t pos) except NULL
# Return value: Borrowed reference.
# Return the object at position pos in the tuple pointed to by
# p. If pos is out of bounds, return NULL and sets an IndexError
......@@ -54,7 +55,7 @@ cdef extern from "Python.h":
# only be used to fill in brand new tuples. Note: This function
# ``steals'' a reference to o.
int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize)
int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize) except -1
# Can be used to resize a tuple. newsize will be the new length of
# the tuple. Because tuples are supposed to be immutable, this
# should only be used if there is only one reference to the
......
cdef extern from "Python.h":
ctypedef void PyObject
ctypedef void PyTypeObject
# The C structure of the objects used to describe built-in types.
############################################################################
......@@ -38,7 +37,7 @@ cdef extern from "Python.h":
object PyType_GenericNew(object type, object args, object kwds)
# Return value: New reference.
bint PyType_Ready(object type)
bint PyType_Ready(object type) except -1
# Finalize a type object. This should be called on all type
# objects to finish their initialization. This function is
# responsible for adding inherited slots from a type's base
......
cdef extern from *:
ctypedef int Py_UNICODE
ctypedef unsigned int Py_UNICODE
# Return true if the object o is a Unicode object or an instance
# of a Unicode subtype. Changed in version 2.2: Allowed subtypes
......
......@@ -69,7 +69,7 @@ cdef void report_unraisable(object e):
# exception has been fetched, in case we are called from
# exception-handling code.
cdef PyObject* NewContext(char* funcname, int lineno, char* filename) except NULL:
cdef PyObject* SetupContext(char* funcname, int lineno, char* filename) except NULL:
if Context is None:
# Context may be None during finalize phase.
# In that case, we don't want to be doing anything fancy
......@@ -143,23 +143,23 @@ cdef void FinishContext(PyObject** ctx):
ctx[0] = NULL
PyErr_Restore(type, value, tb)
cdef extern from "Python.h":
object PyCObject_FromVoidPtr(void*, void (*)(void*))
ctypedef struct RefnannyAPIStruct:
ctypedef struct RefNannyAPIStruct:
void (*INCREF)(PyObject*, PyObject*, int)
void (*DECREF)(PyObject*, PyObject*, int)
void (*GOTREF)(PyObject*, PyObject*, int)
void (*GIVEREF)(PyObject*, PyObject*, int)
PyObject* (*NewContext)(char*, int, char*) except NULL
PyObject* (*SetupContext)(char*, int, char*) except NULL
void (*FinishContext)(PyObject**)
cdef RefnannyAPIStruct api
cdef RefNannyAPIStruct api
api.INCREF = INCREF
api.DECREF = DECREF
api.GOTREF = GOTREF
api.GIVEREF = GIVEREF
api.NewContext = NewContext
api.SetupContext = SetupContext
api.FinishContext = FinishContext
RefnannyAPI = PyCObject_FromVoidPtr(<void*>&api, NULL)
cdef extern from "Python.h":
object PyLong_FromVoidPtr(void*)
RefNannyAPI = PyLong_FromVoidPtr(<void*>&api)
......@@ -31,6 +31,9 @@ def cast(type, arg):
def sizeof(arg):
return 1
def typeof(arg):
return type(arg)
def address(arg):
return pointer(type(arg))([arg])
......
import Cython.Compiler.Errors as Errors
from Cython.CodeWriter import CodeWriter
import unittest
from Cython.Compiler.ModuleNode import ModuleNode
import Cython.Compiler.Main as Main
from Cython.Compiler.TreeFragment import TreeFragment, strip_common_indent
from Cython.Compiler.Visitor import TreeVisitor, VisitorTransform
from Cython.Compiler import TreePath
import unittest
import sys
class NodeTypeWriter(TreeVisitor):
def __init__(self):
super(NodeTypeWriter, self).__init__()
......@@ -107,7 +109,7 @@ class CythonTest(unittest.TestCase):
try:
return func()
except:
self.fail()
self.fail(str(sys.exc_info()[1]))
class TransformTest(CythonTest):
"""
......
#include "Python.h"
#include "embedded.h"
int main(int argc, char *argv) {
Py_Initialize();
initembedded();
spam();
Py_Finalize();
}
print "starting"
def primes(int kmax):
cdef int n, k, i
# cdef int n, k, i
cdef int p[1000]
result = []
if kmax > 1000:
......
......@@ -15,6 +15,8 @@ if len(sys.argv) < 2:
def format_modname(name):
if name.endswith('.pyx'):
name = name[:-4]
elif name.endswith('.py'):
name = name[:-3]
return name.replace('.','_')
modules = [format_modname(x) for x in sys.argv[1:]]
......
......@@ -8,6 +8,16 @@ import shutil
import unittest
import doctest
import operator
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
try:
import cPickle as pickle
except ImportError:
import pickle
WITH_CYTHON = True
......@@ -49,7 +59,11 @@ class build_ext(_build_ext):
def build_extension(self, ext):
if ext.language == 'c++':
try:
self.compiler.compiler_so.remove('-Wstrict-prototypes')
try: # Py2.7+ & Py3.2+
compiler_obj = self.compiler_obj
except AttributeError:
compiler_obj = self.compiler
compiler_obj.compiler_so.remove('-Wstrict-prototypes')
except Exception:
pass
_build_ext.build_extension(self, ext)
......@@ -363,7 +377,7 @@ class CythonRunTestCase(CythonCompileTestCase):
self.setUp()
self.runCompileTest()
if not self.cython_only:
doctest.DocTestSuite(self.module).run(result)
self.run_doctests(self.module, result)
except Exception:
result.addError(self, sys.exc_info())
result.stopTest(self)
......@@ -372,6 +386,95 @@ class CythonRunTestCase(CythonCompileTestCase):
except Exception:
pass
def run_doctests(self, module_name, result):
if sys.version_info[0] >= 3 or not hasattr(os, 'fork'):
doctest.DocTestSuite(module_name).run(result)
return
# fork to make sure we do not keep the tested module loaded
input, output = os.pipe()
child_id = os.fork()
if not child_id:
result_code = 0
try:
output = os.fdopen(output, 'wb')
tests = None
try:
partial_result = PartialTestResult(result)
tests = doctest.DocTestSuite(module_name)
tests.run(partial_result)
except Exception:
if tests is None:
# importing failed, try to fake a test class
tests = _FakeClass(
failureException=None,
**{module_name: None})
partial_result.addError(tests, sys.exc_info())
result_code = 1
pickle.dump(partial_result.data(), output)
finally:
try: output.close()
except: pass
os._exit(result_code)
input = os.fdopen(input, 'rb')
PartialTestResult.join_results(result, pickle.load(input))
cid, result_code = os.waitpid(child_id, 0)
if result_code:
raise Exception("Tests in module '%s' exited with status %d" %
(module_name, result_code >> 8))
is_private_field = re.compile('^_[^_]').match
class _FakeClass(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
try: # Py2.7+ and Py3.2+
from unittest.runner import _TextTestResult
except ImportError:
from unittest import _TextTestResult
class PartialTestResult(_TextTestResult):
def __init__(self, base_result):
_TextTestResult.__init__(
self, self._StringIO(), True,
base_result.dots + base_result.showAll*2)
def strip_error_results(self, results):
for test_case, error in results:
for attr_name in filter(is_private_field, dir(test_case)):
if attr_name == '_dt_test':
test_case._dt_test = _FakeClass(
name=test_case._dt_test.name)
else:
setattr(test_case, attr_name, None)
def data(self):
self.strip_error_results(self.failures)
self.strip_error_results(self.errors)
return (self.failures, self.errors, self.testsRun,
self.stream.getvalue())
def join_results(result, data):
"""Static method for merging the result back into the main
result object.
"""
errors, failures, tests_run, output = data
if output:
result.stream.write(output)
result.errors.extend(errors)
result.failures.extend(failures)
result.testsRun += tests_run
join_results = staticmethod(join_results)
class _StringIO(StringIO):
def writeln(self, line):
self.write("%s\n" % line)
class CythonUnitTestCase(CythonCompileTestCase):
def shortDescription(self):
return "compiling (%s) tests in %s" % (self.language, self.module)
......@@ -606,6 +709,10 @@ if __name__ == '__main__':
compile as cython_compile
from Cython.Compiler import Errors
Errors.LEVEL = 0 # show all warnings
from Cython.Compiler import Options
Options.generate_cleanup_code = 3 # complete cleanup code
from Cython.Compiler import DebugFlags
DebugFlags.debug_temp_code_comments = 1
# RUN ALL TESTS!
UNITTEST_MODULE = "Cython"
......@@ -621,8 +728,6 @@ if __name__ == '__main__':
if WITH_CYTHON:
from Cython.Compiler.Version import version
sys.stderr.write("Running tests against Cython %s\n" % version)
from Cython.Compiler import DebugFlags
DebugFlags.debug_temp_code_comments = 1
else:
sys.stderr.write("Running tests without Cython.\n")
sys.stderr.write("Python %s\n" % sys.version)
......@@ -634,7 +739,7 @@ if __name__ == '__main__':
build_in_temp=True,
pyxbuild_dir=os.path.join(WORKDIR, "support"))
sys.path.insert(0, os.path.split(libpath)[0])
CFLAGS.append("-DCYTHON_REFNANNY")
CFLAGS.append("-DCYTHON_REFNANNY=1")
test_bugs = False
if options.tickets:
......
......@@ -5,6 +5,6 @@ methodmangling_T5
class_attribute_init_values_T18
numpy_ValueError_T172
unsignedbehaviour_T184
funcexc_iter_T228
bad_c_struct_T252
missing_baseclass_in_predecl_T262
extended_unpacking_T409
......@@ -2,6 +2,7 @@ cdef void foo():
cdef int i1, i2=0
cdef char c1=0, c2
cdef char *p1, *p2=NULL
cdef object obj1
i1 = i2
i1 = c1
p1 = p2
......
......@@ -12,6 +12,9 @@ cdef double spam "c_spam" (int i, float f):
cdef foo *p
global b
d = spam(a, f)
cdef foo q
q.i = 7
p = &q
b = p.i
p.i = x
p.i = y
......
......@@ -14,6 +14,6 @@ a.some_method(1, 2)
a.some_method(1, y=2)
_ERRORS = u"""
9:13: Keyword arguments not allowed in cdef functions.
14:13: Keyword arguments not allowed in cdef functions.
9:13: Keyword and starred arguments not allowed in cdef functions.
14:13: Keyword and starred arguments not allowed in cdef functions.
"""
......@@ -2,9 +2,17 @@ cdef void foo():
cdef int bool, int1
cdef char *ptr2
cdef int *ptr3
cdef object i = 5
bool = i == ptr2 # evaluated in Python space
bool = ptr3 == i # error
bool = int1 == ptr2 # error
bool = ptr2 == ptr3 # error
bool = 1 in 2 in 3
_ERRORS = u"""
5:13: Invalid types for '==' (int, char *)
6:13: Invalid types for '==' (char *, int *)
8:13: Invalid types for '==' (int *, Python object)
9:13: Invalid types for '==' (int, char *)
10:13: Invalid types for '==' (char *, int *)
"""
......@@ -3,11 +3,13 @@ cdef int c2 = "te" # fails
cdef int cx = "test" # fails
cdef int x1 = "\xFF" # works
cdef int x2 = u"\xFF" # fails
cdef int x2 = "\u0FFF" # fails
cdef int x3 = u"\xFF" # fails
_ERRORS = u"""
2:14: Only single-character byte strings can be coerced into ints.
3:14: Only single-character byte strings can be coerced into ints.
6:14: Unicode objects do not support coercion to C types.
2:14: Only single-character strings can be coerced into ints.
3:14: Only single-character strings can be coerced into ints.
6:15: Only single-character strings can be coerced into ints.
7:14: Unicode objects do not support coercion to C types.
"""
......@@ -96,10 +96,14 @@ _ERRORS = u"""
28:16: Constructing complex number not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil
30:8: Backquote expression not allowed without gil
30:9: Operation not allowed without gil
31:15: Assignment of Python object not allowed without gil
31:15: Operation not allowed without gil
31:15: Python import not allowed without gil
32:8: Operation not allowed without gil
32:13: Python import not allowed without gil
32:25: Constructing Python list not allowed without gil
32:25: Operation not allowed without gil
33:17: Iterating over Python object not allowed without gil
35:11: Indexing Python object not allowed without gil
36:11: Slicing Python object not allowed without gil
......
import somemod.child
cdef somemod.child.something x
_ERRORS = u"""
3:5: 'somemod.child' is not a cimported module
"""
......@@ -5,5 +5,5 @@ cdef void* allowed = <void*>a
cdef double* disallowed = <double*>a
_ERRORS = u"""
5:26: Python objects cannot be casted to pointers of primitive types
5:26: Python objects cannot be cast to pointers of primitive types
"""
# coding: ASCII
# ok:
cdef char* c1 = "abc"
cdef str s1 = "abc"
cdef unicode u1 = u"abc"
cdef bytes b1 = b"abc"
cdef char* c2 = b"abc"
cdef bytes b2 = c1
cdef char* c3 = b1
cdef object o1 = "abc"
cdef object o2 = b"abc"
cdef object o3 = u"abc"
o4 = c1
o5 = b1
o6 = s1
o7 = u1
# errors:
cdef char* c_f1 = u"abc"
cdef char* c_f2 = u1
cdef char* c_f3 = s1
cdef bytes b_f1 = u"abc"
cdef bytes b_f2 = u1
cdef bytes b_f3 = s1
cdef str s_f1 = b"abc"
cdef str s_f2 = b1
cdef str s_f3 = u"abc"
cdef str s_f4 = u1
cdef unicode u_f1 = "abc"
cdef unicode u_f2 = s1
cdef unicode u_f3 = b"abc"
cdef unicode u_f4 = b1
cdef unicode u_f5 = c1
cdef tuple t_f1 = "abc"
cdef tuple t_f2 = u"abc"
cdef tuple t_f3 = b"abc"
cdef list l_f1 = s1
cdef list l_f2 = b1
cdef list l_f3 = u1
_ERRORS = u"""
25:20: Unicode objects do not support coercion to C types.
26:22: Unicode objects do not support coercion to C types.
27:22: 'str' objects do not support coercion to C types (use 'bytes'?).
29:20: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
30:22: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
31:22: Cannot convert 'str' to 'bytes' implicitly. This is not portable.
33:17: Cannot assign type 'char *' to 'str object'
34:19: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
35:17: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
36:19: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
38:20: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
39:22: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
40:20: Cannot assign type 'char *' to 'unicode object'
41:22: Cannot convert 'bytes' object to unicode implicitly, decoding required
42:22: Cannot convert 'char*' to unicode implicitly, decoding required
44:19: Cannot assign type 'str object' to 'tuple object'
45:18: Cannot assign type 'unicode object' to 'tuple object'
46:18: Cannot assign type 'char *' to 'tuple object'
"""
def f():
print assert sizeof(int) == sizof(short) == sizeof(long)
_ERRORS = u"""
3:10: Expected an identifier or literal
"""
__doc__ = u"""
__getattribute__ and __getattr__ special methods for a single class.
"""
cdef class just_getattribute:
"""
>>> a = just_getattribute()
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
"""
def __getattribute__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
cdef class just_getattr:
"""
>>> a = just_getattr()
>>> a.foo
10
......@@ -16,45 +27,37 @@ __getattribute__ and __getattr__ special methods for a single class.
>>> a.invalid
Traceback (most recent call last):
AttributeError
>>> a = both()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
"""
cdef class just_getattribute:
def __getattribute__(self,n):
if n == u'bar':
return n
else:
raise AttributeError
cdef class just_getattr:
"""
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattr__(self,n):
if n == u'bar':
if n == 'bar':
return n
else:
raise AttributeError
cdef class both:
"""
>>> a = both()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
"""
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattribute__(self,n):
if n == u'foo':
if n == 'foo':
return self.foo
else:
raise AttributeError
def __getattr__(self,n):
if n == u'bar':
if n == 'bar':
return n
else:
raise AttributeError
......@@ -8,10 +8,11 @@ which makes the test flow a bit untraditional. Both
module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = __test__.items()
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print key, ';', value
... print('%s ; %s' % (key, value))
MyCdefClass.cpdef_method (line 78) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 75) ; >>> add_log("cdef class method")
MyClass.method (line 65) ; >>> add_log("class method")
doc_without_test (line 47) ; Some docs
......@@ -22,7 +23,6 @@ myfunc (line 44) ; >>> add_log("def")
log = []
cdef cdeffunc():
"""
Please don't include me!
......@@ -75,3 +75,39 @@ cdef class MyCdefClass:
def method(self):
""">>> add_log("cdef class method")"""
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __dealloc__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __richcmp__(self, other, int op):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
def __nonzero__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
__doc__ = u"""
>>> foo(True, False, 23, 'test', 1)
(0, 1, False, False)
(0.0, 1.0, False, False)
"""
def foo(obj1, obj2, obj3, obj4, obj5):
cdef int bool1, bool2, bool3, bool4
cdef char *ptr
cdef int bool1, bool2
cdef float bool3, bool4
cdef char *ptr1, *ptr2, *ptr0
cdef float f
bool1 = 1
bool2 = 0
ptr = NULL
ptr1 = ptr2 = NULL
f = 0.0
bool3 = bool1 and bool2
bool3 = bool1 or bool2
bool3 = obj1 and obj2
bool3 = bool1 and ptr
ptr0 = ptr1 and ptr2
bool3 = bool1 and f
bool4 = bool1 and bool2 and bool3
bool4 = bool1 or bool2 and bool3
......
......@@ -11,11 +11,15 @@ if sys.version_info[0] >= 3:
b'abcdefg'
>>> m1 = memoryview(b1)
__getbuffer__ called
>>> m1.tobytes()
__getbuffer__ called
b'abcdefg'
>>> m2 = memoryview(b2)
__getbuffer__ called
>>> m2.tobytes()
__getbuffer__ called
releasing!
b'abcdefg'
......@@ -24,10 +28,11 @@ b'abcdefg'
releasing!
"""
s = "abcdefg"
s = b"abcdefg"
cdef class TestBuffer:
def __getbuffer__(self, Py_buffer* buffer, int flags):
print u"__getbuffer__ called"
buffer.buf = <char*>s
buffer.obj = self
buffer.len = len(s)
......
def f():
"""
>>> f()
True
True
"""
cdef char a
a = 62
print (a == '>')
print (a == <char>'>')
__doc__ = u"""
>>> test_object_conversion(2)
((2+0j), (2+0j))
((2+0j), (2+0j), (2+0j))
>>> test_object_conversion(2j - 0.5)
((-0.5+2j), (-0.5+2j))
((-0.5+2j), (-0.5+2j), (-0.5+2j))
>>> test_arithmetic(2j, 4j)
(-2j, 6j, -2j, (-8+0j), (0.5+0j))
(2j, -2j, 6j, -2j, (-8+0j), (0.5+0j))
>>> test_arithmetic(6+12j, 3j)
((-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j))
((6+12j), (-6-12j), (6+15j), (6+9j), (-36+18j), (4-2j))
>>> test_arithmetic(5-10j, 3+4j)
((-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
((5-10j), (-5+10j), (8-6j), (2-14j), (55-10j), (-1-2j))
>>> test_div_by_zero(4j)
-0.25j
>>> test_div_by_zero(0)
Traceback (most recent call last):
...
ZeroDivisionError: float division
## XXX this is not working
## >>> test_div_by_zero(4j)
## -0.25j
## >>> test_div_by_zero(0)
## Traceback (most recent call last):
## ...
## ZeroDivisionError: float division
>>> test_coercion(1, 1.5, 2.5, 4+1j, 10j)
(1+0j)
......@@ -56,6 +57,12 @@ __doc__ = u"""
(1+2j)
>>> test_real_imag_assignment(1.5, -3.5)
(1.5-3.5j)
>>> test_conjugate(2+3j)
(2-3j)
>>> test_conjugate_double(2+3j)
(2-3j)
"""
#cdef extern from "complex.h":
......@@ -65,15 +72,17 @@ cimport cython
def test_object_conversion(o):
cdef float complex a = o
cdef double complex z = o
return (a, z)
cdef double complex b = o
cdef long double complex c = o
return (a, b, c)
def test_arithmetic(double complex z, double complex w):
return -z, z+w, z-w, z*w, z/w
return +z, -z, z+w, z-w, z*w, z/w
@cython.cdivision(False)
def test_div_by_zero(double complex z):
return 1/z
## XXX this is not working
## @cython.cdivision(False)
## def test_div_by_zero(double complex z):
## return 1/z
def test_coercion(int a, float b, double c, float complex d, double complex e):
cdef double complex z
......@@ -102,3 +111,13 @@ def test_real_imag_assignment(object a, double b):
z.imag = b
return z
def test_conjugate(float complex z):
return z.conjugate()
def test_conjugate_double(double complex z):
return z.conjugate()
ctypedef double complex cdouble
def test_conjugate_typedef(cdouble z):
return z.conjugate()
cdef extern from "complex_numbers_c89_T398.h": pass
include "complex_numbers_T305.pyx"
#if !defined(__cplusplus)
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) \
|| defined(__GNUC__) \
|| defined(__INTEL_COMPILER) \
|| defined(__IBMC__) \
#include <complex.h>
#if !defined(_Complex_I)
#error The "complex.h" header does not define the '_Complex_I' macro.
#error Please report this to Cython developers <cython-dev@codespeak.net>
#endif
#endif
#endif
cdef extern from "complex_numbers_c99_T398.h": pass
include "complex_numbers_T305.pyx"
#if defined(__cplusplus)
#define CYTHON_CCOMPLEX 1
#else
#define CYTHON_CCOMPLEX 0
#endif
cdef extern from "complex_numbers_cxx_T398.h": pass
include "complex_numbers_T305.pyx"
__doc__ = """
>>> A().is_True()
True
>>> A().is_False()
False
>>> B().is_True()
True
>>> B().is_False()
False
"""
cdef class A:
cpdef is_True(self):
return True
cpdef is_False(self):
return not self.is_True()
class B(A):
def is_True(self):
return True
typedef struct {
int x;
} MyStruct;
__doc__ = """
>>> f()
{'x': 1}
"""
cimport crashT245_pxd
def f():
cdef crashT245_pxd.MyStruct s
s.x = 1
print s
cdef extern from "crashT245.h":
ctypedef struct MyStruct:
int x
__doc__ = u"""
>>> y
(b'1', b'2', b'3')
('1', '2', '3')
>>> x
b'1foo2foo3'
'1foo2foo3'
"""
import sys
if sys.version_info[0] < 3:
__doc__ = __doc__.replace(u"b'", u"'")
y = ('1','2','3')
......
......@@ -41,7 +41,7 @@ DEF INT2 = 0x42
DEF INT3 = -0x42
DEF LONG = 666L
DEF FLOAT = 12.5
DEF STR = "spam"
DEF STR = b"spam"
DEF TWO = TUPLE[1]
DEF FIVE = TWO + 3
DEF TRUE = TRUE_FALSE[0]
......
__doc__ = u"""
>>> test_int(0)
False
>>> test_int(1)
True
>>> test_short(0)
False
>>> test_short(1)
True
>>> test_Py_ssize_t(0)
False
>>> test_Py_ssize_t(1)
True
>>> test_ptr()
False
>>> test_ptr2()
2
>>> test_attr_int(TestExtInt(0))
False
>>> test_attr_int(TestExtInt(1))
True
>>> test_attr_ptr(TestExtPtr(0))
False
>>> test_attr_ptr(TestExtPtr(1))
True
"""
def test_ptr():
cdef void* p = NULL
if p:
return True
else:
return False
def test_ptr2():
cdef char* p1 = NULL
cdef char* p2 = NULL
p1 += 1
if p1 and p2:
return 1
elif p1 or p2:
return 2
else:
return 3
def test_int(int i):
if i:
return True
else:
return False
def test_short(short i):
if i:
return True
else:
return False
def test_Py_ssize_t(Py_ssize_t i):
if i:
return True
else:
return False
cdef class TestExtInt:
cdef int i
def __init__(self, i): self.i = i
def test_attr_int(TestExtInt e):
if e.i:
return True
else:
return False
cdef class TestExtPtr:
cdef void* p
def __init__(self, int i): self.p = <void*>i
def test_attr_ptr(TestExtPtr e):
if e.p:
return True
else:
return False
......@@ -576,15 +576,15 @@ def test_DefSInt(defs.SInt x):
"""
return x
def test_DefUInt(defs.UInt x):
def test_DefUChar(defs.UChar x):
u"""
>>> test_DefUInt(-1) #doctest: +ELLIPSIS
>>> test_DefUChar(-1) #doctest: +ELLIPSIS
Traceback (most recent call last):
...
OverflowError: ...
>>> test_DefUInt(0)
>>> test_DefUChar(0)
0
>>> test_DefUInt(1)
>>> test_DefUChar(1)
1
"""
return x
......
......@@ -68,10 +68,10 @@ __doc__ = ur"""
'with_doc_4(int a, str b, list c) -> str\n\n Existing string\n '
>>> f_sd.__doc__
"f_sd(str s=u'spam')"
"f_sd(str s='spam')"
>>> cf_sd.__doc__
"cf_sd(str s=u'spam') -> str"
"cf_sd(str s='spam') -> str"
>>> types.__doc__
'types(Ext a, int b, unsigned short c, float d, e)'
......@@ -137,10 +137,6 @@ __doc__ = ur"""
"""
import sys
if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u"u'spam'", u"'spam'")
cdef class Ext:
def __init__(self, a, b, c=None):
......@@ -219,10 +215,10 @@ cpdef str with_doc_4(int a, str b, list c):
"""
return b
def f_sd(str s=u'spam'):
def f_sd(str s='spam'):
return s
cpdef str cf_sd(str s=u'spam'):
cpdef str cf_sd(str s='spam'):
return s
cpdef char f_c(char c):
......
__doc__ = """
>>> simple()
(1, 2, [1, 2], [1, 2])
>>> extended()
(1, (), 2, [1, 2], [1, 2])
"""
def simple():
a, c = d = e = [1,2]
return a, c, d, e
def extended():
a, *b, c = d = e = [1,2]
return a, b, c, d, e
__doc__ = u"""
>>> test_modify()
0 1 2 3 4
0
1
2
3
4
<BLANKLINE>
(4, 0)
>>> test_fix()
0 1 2 3 4
0
1
2
3
4
<BLANKLINE>
4
>>> test_break()
0 1 2
0
1
2
<BLANKLINE>
(2, 0)
>>> test_return()
0 1 2
0
1
2
(2, 0)
"""
......@@ -20,7 +35,7 @@ cimport cython
def test_modify():
cdef int i, n = 5
for i in range(n):
print i,
print i
n = 0
print
return i,n
......@@ -30,7 +45,7 @@ def test_modify():
def test_fix():
cdef int i
for i in range(5):
print i,
print i
print
return i
......@@ -39,10 +54,12 @@ def test_fix():
def test_break():
cdef int i, n = 5
for i in range(n):
print i,
print i
n = 0
if i == 2:
break
else:
print "FAILED!"
print
return i,n
......@@ -51,7 +68,7 @@ def test_break():
def test_return():
cdef int i, n = 5
for i in range(n):
print i,
print i
n = 0
if i == 2:
return i,n
......
......@@ -45,8 +45,8 @@ True
"""
import sys
IS_PY3 = sys.version_info[0] >= 3
if sys.version_info[0] < 3:
sys.exc_clear()
cdef class cy_iterator(object):
def __iter__(self):
......
__doc__ = u"""
>>> def bar():
... try:
... foo()
... except ValueError:
... pass
>>> bar()
>>> print(sys.exc_info())
(None, None, None)
"""
import sys
if sys.version_info[0] < 3:
sys.exc_clear()
def foo():
try:
raise TypeError
except TypeError:
raise ValueError
import sys
def reraise(f, exc):
"""
>>> def f(exc): raise exc
>>> reraise(f, TypeError)
Traceback (most recent call last):
TypeError
>>> def f(exc): raise exc('hiho')
>>> reraise(f, TypeError)
Traceback (most recent call last):
TypeError: hiho
"""
try:
f(exc)
except:
assert sys.exc_info()[0] is exc, str(sys.exc_info()[1])
raise
def reraise_original(f, exc, raise_catch):
"""
>>> def f(exc): raise exc
>>> def raise_catch_py():
... try: raise ValueError
... except: pass
>>> reraise_original(f, TypeError, raise_catch_py)
Traceback (most recent call last):
TypeError
>>> reraise_original(f, TypeError, raise_catch_cy)
Traceback (most recent call last):
TypeError
>>> reraise_original(f, TypeError, raise_catch_cy_non_empty)
Traceback (most recent call last):
TypeError
"""
try:
f(exc)
except:
raise_catch()
assert sys.exc_info()[0] is exc, str(sys.exc_info()[1])
raise
def raise_catch_cy():
try: raise ValueError
except: pass
def raise_catch_cy_non_empty():
try: raise ValueError
except:
a = 1+1
......@@ -46,6 +46,15 @@ __doc__ = u"""
>>> q(1)
Traceback (most recent call last):
TypeError: 'NoneType' object is not iterable
>>> l = [1,2,3,4]
>>> l2 = [l[1:],l[:-1],l]
>>> 2 in l in l2
True
>>> r(2)
1
>>> s(2)
1
"""
def f(a,b):
......@@ -87,3 +96,13 @@ def q(a):
cdef dict d = None
cdef int result = a in d # should fail with a TypeError
return result
def r(a):
l = [1,2,3,4]
l2 = [l[1:],l[:-1],l]
cdef int result = a in l in l2
return result
def s(a):
cdef int result = a in [1,2,3,4] in [[1,2,3],[2,3,4],[1,2,3,4]]
return result
......@@ -35,7 +35,7 @@ def test_all():
assert not isinstance(u"foo", int)
# Non-optimized
foo = A
cdef object foo = A
assert isinstance(A(), foo)
assert isinstance(0, (int, long))
assert not isinstance(u"xyz", (int, long))
......
__doc__ = u"""
>>> py_x = br'\\\\'
>>> assert x == py_x
>>> b == br'\\\\'
True
>>> s == r'\\\\'
True
>>> u == ur'\\\\'
True
"""
import sys
if sys.version_info[0] < 3:
__doc__ = __doc__.replace(u" br'", u" r'")
else:
__doc__ = __doc__.replace(u" ur'", u" r'")
x = r'\\'
b = br'\\'
s = r'\\'
u = ur'\\'
__doc__ = u"""
>>> f()
>>> uf()
It works!
>>> bf()
It works!
"""
DEF STUFF = "Spam"
DEF USTUFF = u"Spam"
def uf():
IF USTUFF == u"Spam":
print "It works!"
ELSE:
print "Doesn't work"
DEF BSTUFF = b"Spam"
def f():
IF STUFF == "Spam":
print u"It works!"
def bf():
IF BSTUFF == b"Spam":
print "It works!"
ELSE:
print u"Doesn't work"
print "Doesn't work"
__doc__ = u"""
>>> x = X()
>>> x.slots
[b'']
['']
"""
import sys
if sys.version_info[0] < 3:
__doc__ = __doc__.replace(u"b'", u"'")
class X:
slots = ["", ]
......@@ -23,7 +23,7 @@ def test_ints(int x):
return L[3], Li[3], Lii[1][0]
def test_chars(foo):
cdef char** ss = ["a", "bc", foo]
cdef char** ss = [b"a", b"bc", foo]
return ss[0], ss[1], ss[2]
cdef struct MyStruct:
......
......@@ -37,7 +37,7 @@ double quoted string."""
i = 'This string\
has an ignored newline.'
j = 'One-char escapes: \'\"\\\a\b\f\n\r\t\v'
k = 'Oct and hex escapes: \1 \12 \123 \x45 \xaf \xAF'
k = b'Oct and hex escapes: \1 \12 \123 \x45 \xaf \xAF'
l = r'''This is\
a \three \line
raw string with some backslashes.'''
......@@ -50,7 +50,8 @@ with ' and " quotes"""
q = "NameLikeString2"
r = "99_percent_un_namelike"
s = "Not an \escape"
t = b'this' b'parrot' b'is' b'resting'
u = u'this' u'parrot' u'is' u'resting'
def test_float(x):
......
__doc__ = u"""
>>> test_str(1)
b'b'
'b'
>>> test_unicode_ascii(2)
u'c'
......@@ -10,14 +10,14 @@ __doc__ = u"""
>>> test_int_list(2)
3
>>> test_str_list(1)
b'bcd'
'bcd'
>>> test_int_tuple(2)
3
>>> test_str_tuple(0)
b'a'
'a'
>>> test_mix_tuple(1)
b'abc'
'abc'
>>> test_mix_tuple(0)
1
"""
......@@ -30,9 +30,6 @@ else:
__doc__ = __doc__.replace(u" b'", u" '")
def test_str(n):
if IS_PY3:
return bytes(["abcd"[n]])
else:
return "abcd"[n]
def test_unicode_ascii(n):
......
__doc__ = u"""
>>> swap(1,2)
(2, 1)
"""
def swap(a,b):
a,b = b,a
return a,b
......@@ -5,6 +5,7 @@ __doc__ = u"""
def f():
cdef int bool, int1, int2
cdef object obj1, obj2
int1 = 0
int2 = 0
obj1 = 1
......
......@@ -13,9 +13,9 @@ doctest = u"""# Python 3 gets all of these right ...
'This is a function docstring.'
>>> C.__doc__
u'This is a class docstring.'
'This is a class docstring.'
>>> CS.__doc__
u'This is a subclass docstring.'
'This is a subclass docstring.'
>>> print(CSS.__doc__)
None
......
__doc__ = u"""
>>> boolExpressionsFail()
u'Not 2b'
'Not 2b'
"""
import sys
if sys.version_info[0] >= 3:
__doc__ = __doc__.replace(u" u'", u" '")
def boolExpressionsFail():
dict = {1: 1}
if not "2b" in dict:
return u"Not 2b"
return "Not 2b"
else:
return u"2b?"
return "2b?"
__doc__ = """# disabled in Py3
import sys
if sys.version_info[0] < 3:
__doc__ = u"""
>>> test(0)
0L
>>> test(1)
1L
>>> import sys
>>> sys.maxint + 1 > sys.maxint
True
>>> type(sys.maxint * 2 + 1) is long
......@@ -19,7 +22,16 @@ __doc__ = """# disabled in Py3
True
>>> test(256 ** unsigned_long_size() - 1) > sys.maxint
True
"""
"""
else:
__doc__ = u"""
>>> test(0)
0
>>> test(1)
1
>>> test(256 ** unsigned_long_size() - 1) > 0
True
"""
def test(k):
cdef unsigned long m
......
cdef long foo(long x):
print "foo(%s)" % x
return x
def test_or(long a, long b):
"""
>>> test_or(1,2)
foo(1)
1
>>> test_or(1,0)
foo(1)
1
>>> test_or(0,2)
foo(0)
foo(2)
2
>>> test_or(0,0)
foo(0)
foo(0)
0
"""
print foo(a) or foo(b)
def test_and(long a, long b):
"""
>>> test_and(1,2)
foo(1)
foo(2)
2
>>> test_and(1,0)
foo(1)
foo(0)
0
>>> test_and(0,2)
foo(0)
0
>>> test_and(0,0)
foo(0)
0
"""
print foo(a) and foo(b)
__doc__ = u"""
>>> test_eq()
True
True
True
True
>>> test_cascaded_eq()
True
True
True
True
True
True
True
True
>>> test_cascaded_ineq()
True
True
True
True
True
True
True
True
>>> test_long_ineq()
True
>>> test_long_ineq_py()
True
True
"""
cdef int i = 'x'
cdef char c = 'x'
cdef char* s = 'x'
def test_eq():
print i == 'x'
print i == c'x'
print c == 'x'
print c == c'x'
# print s == 'x' # error
# print s == c'x' # error
def test_cascaded_eq():
print 'x' == i == 'x'
print 'x' == i == c'x'
print c'x' == i == 'x'
print c'x' == i == c'x'
print 'x' == c == 'x'
print 'x' == c == c'x'
print c'x' == c == 'x'
print c'x' == c == c'x'
def test_cascaded_ineq():
print 'a' <= i <= 'z'
print 'a' <= i <= c'z'
print c'a' <= i <= 'z'
print c'a' <= i <= c'z'
print 'a' <= c <= 'z'
print 'a' <= c <= c'z'
print c'a' <= c <= 'z'
print c'a' <= c <= c'z'
def test_long_ineq():
print 'a' < 'b' < 'c' < 'd' < c < 'y' < 'z'
def test_long_ineq_py():
print 'abcdef' < 'b' < 'c' < 'd' < 'y' < 'z'
print 'a' < 'b' < 'cde' < 'd' < 'y' < 'z'
# -*- coding: latin-1 -*-
__doc__ = (u"""
>>> a == 'abc'
True
>>> isinstance(a, str)
True
>>> isinstance(s, str)
True
>>> len(s)
6
>>> s == 'ao'
True
>>> isinstance(add(), str)
True
>>> len(add())
9
>>> add() == 'abcao'
True
>>> isinstance(add_literal(), str)
True
>>> len(add_literal())
9
>>> add_literal() == 'abcao'
True
>>> isinstance(typed(), str)
True
>>> len(typed())
6
>>> typed() == ''
True
"""
# recoding/escaping is required to properly pass the literals to doctest
).encode('unicode_escape').decode('ASCII')
a = 'abc'
s = 'ao'
u = u'ao'
cdef str S = ''
def add():
return a+s
def add_literal():
return 'abc' + 'ao'
def typed():
return S
__doc__ = u"""
>>> c = C()
>>> c.x
b'foo'
'foo'
"""
import sys
if sys.version_info[0] < 3:
__doc__ = __doc__.replace(u" b'", u" '")
class C:
x = "foo"
__doc__ = u"""
>>> s('test', **encoding)
b'test'
>>> str('test')
'test'
>>> z
b'test'
'test'
>>> c('testing')
b'testing'
'testing'
>>> sub('testing a subtype')
b'testing a subtype'
>>> subs('testing a subtype', **encoding)
b'testing a subtype'
'testing a subtype'
>>> subs('testing a subtype')
'testing a subtype'
# >>> csub('testing a subtype')
# 'testing a subtype'
......@@ -16,27 +16,20 @@ __doc__ = u"""
# 'testing a subtype'
"""
import sys
if sys.version_info[0] >= 3:
encoding = {u'encoding' : u'ASCII'}
else:
encoding = {}
__doc__ = __doc__.replace(u" b'", u" '")
s = str
z = str('test')
def c(string):
return str(string, **encoding)
return str(string)
class subs(str):
pass
def sub(string):
return subs(string, **encoding)
return subs(string)
#cdef class subs(str):
# pass
#def csub(string):
# return csubs(string, **encoding)
# return csubs(string)
__doc__ = ur"""
>>> s1
b'abc\x11'
>>> s1 == b'abc\x11'
'abc\x11'
>>> s1 == 'abc\x11'
True
>>> len(s1)
4
>>> s2
b'abc\\x11'
>>> s2 == br'abc\x11'
'abc\\x11'
>>> s2 == r'abc\x11'
True
>>> len(s2)
7
>>> s3
b'abc\\x11'
>>> s3 == bR'abc\x11'
'abc\\x11'
>>> s3 == R'abc\x11'
True
>>> len(s3)
7
......
__doc__ = """
>>> foo()
([0, 0], [0, 0])
"""
# Extracted from sage/plot/plot3d/index_face_set.pyx:502
# Turns out to be a bug in implementation of PEP 3132 (Extended Iterable Unpacking)
def foo():
a = b = [0,0]
return a, b
# cython: infer_types = True
__doc__ = u"""
>>> simple()
>>> multiple_assignments()
>>> arithmatic()
>>> cascade()
>>> increment()
>>> loop()
"""
from cython cimport typeof
def simple():
i = 3
assert typeof(i) == "long", typeof(i)
x = 1.41
assert typeof(x) == "double", typeof(x)
xptr = &x
assert typeof(xptr) == "double *", typeof(xptr)
xptrptr = &xptr
assert typeof(xptrptr) == "double **", typeof(xptrptr)
b = b"abc"
assert typeof(b) == "char *", typeof(b)
s = "abc"
assert typeof(s) == "str object", typeof(s)
u = u"xyz"
assert typeof(u) == "unicode object", typeof(u)
L = [1,2,3]
assert typeof(L) == "list object", typeof(L)
t = (4,5,6)
assert typeof(t) == "tuple object", typeof(t)
def multiple_assignments():
a = 3
a = 4
a = 5
assert typeof(a) == "long"
b = a
b = 3.1
b = 3.14159
assert typeof(b) == "double"
c = a
c = b
c = [1,2,3]
assert typeof(c) == "Python object"
def arithmatic():
a = 1 + 2
assert typeof(a) == "long"
b = 1 + 1.5
assert typeof(b) == "double"
c = 1 + <object>2
assert typeof(c) == "Python object"
d = "abc %s" % "x"
assert typeof(d) == "Python object"
def cascade():
a = 1.0
b = a + 2
c = b + 3
d = c + 4
assert typeof(d) == "double"
e = a + b + c + d
assert typeof(e) == "double"
def cascaded_assignment():
a = b = c = d = 1.0
assert typeof(a) == "double"
assert typeof(b) == "double"
assert typeof(c) == "double"
assert typeof(d) == "double"
e = a + b + c + d
assert typeof(e) == "double"
def increment():
a = 5
a += 1
assert typeof(a) == "long"
def loop():
for a in range(10):
pass
assert typeof(a) == "long"
b = 1.0
for b in range(5):
pass
assert typeof(b) == "double"
for c from 0 <= c < 10 by .5:
pass
assert typeof(c) == "double"
for d in range(0, 10L, 2):
pass
assert typeof(a) == "long"
......@@ -52,13 +52,13 @@ def slice_list_assign(list l, value):
def slice_charp(py_string_arg):
cdef str py_string = py_string_arg.encode(u'ASCII')
cdef bytes py_string = py_string_arg.encode(u'ASCII')
cdef char* s = py_string
return s[1:3].decode(u'ASCII')
def slice_charp_repeat(py_string_arg):
cdef str py_string = py_string_arg.encode(u'ASCII')
cdef bytes py_string = py_string_arg.encode(u'ASCII')
cdef char* s = py_string
cdef str slice_val = s[1:6]
cdef bytes slice_val = s[1:6]
s = slice_val
return s[1:3].decode(u'ASCII')
import math
cdef class MyClass:
"""
>>> x=MyClass()
4
"""
def __cinit__(self, int arg=2*2):
print arg
cdef class MyOtherClass:
"""
>>> x=MyOtherClass()
8
"""
def __cinit__(self, int arg=4*int(math.sqrt(4))):
print arg
__doc__ = u"""
>>> simple()
int
long
long long
int *
int **
A
B
X
Python object
>>> expression()
double
double complex
int
unsigned int
"""
from cython cimport typeof
cdef class A:
pass
cdef class B(A):
pass
cdef struct X:
double a
double complex b
def simple():
cdef int i = 0
cdef long l = 0
cdef long long ll = 0
cdef int* iptr = &i
cdef int** iptrptr = &iptr
cdef A a = None
cdef B b = None
cdef X x = X(a=1, b=2)
print typeof(i)
print typeof(l)
print typeof(ll)
print typeof(iptr)
print typeof(iptrptr)
print typeof(a)
print typeof(b)
print typeof(x)
print typeof(None)
used = i, l, ll, <long>iptr, <long>iptrptr, a, b, x
def expression():
cdef X x = X(a=1, b=2)
cdef X *xptr = &x
cdef short s = 0
cdef int i = 0
cdef unsigned int ui = 0
print typeof(x.a)
print typeof(xptr.b)
print typeof(s + i)
print typeof(i + ui)
used = x, <long>xptr, s, i, ui
# -*- coding: utf-8 -*-
__doc__ = r"""
__doc__ = br"""
>>> sa
b'abc'
'abc'
>>> ua
u'abc'
>>> b
......@@ -19,7 +19,7 @@ __doc__ = r"""
u'S\xf8k ik\xfc\xd6\xe4abc'
>>> null
u'\x00'
""".decode(u"ASCII") + """
""".decode("ASCII") + b"""
>>> len(sa)
3
>>> len(ua)
......@@ -38,7 +38,7 @@ __doc__ = r"""
12
>>> len(null)
1
""".decode(u"ASCII") + u"""
""".decode("ASCII") + u"""
>>> ua == u'abc'
True
>>> b == u'123'
......
......@@ -6,9 +6,9 @@
# This file is written in UTF-8, but it has no encoding declaration,
# so it just defaults to UTF-8 (PEP 3120).
__doc__ = r"""
__doc__ = br"""
>>> sa
b'abc'
'abc'
>>> ua
u'abc'
>>> b
......@@ -25,7 +25,7 @@ __doc__ = r"""
u'S\xf8k ik\xfc\xd6\xe4abc'
>>> null
u'\x00'
""".decode(u"ASCII") + """
""".decode("ASCII") + b"""
>>> len(sa)
3
>>> len(ua)
......@@ -44,7 +44,7 @@ __doc__ = r"""
12
>>> len(null)
1
""".decode(u"ASCII") + u"""
""".decode("ASCII") + u"""
>>> ua == u'abc'
True
>>> b == u'123'
......
# -*- coding: latin-1 -*-
__doc__ = r"""
__doc__ = br"""
>>> sa
b'abc'
'abc'
>>> ua
u'abc'
>>> b
......@@ -19,7 +19,7 @@ __doc__ = r"""
u'S\xf8k ik\xfc\xd6\xe4abc'
>>> null
u'\x00'
""".decode(u"ASCII") + """
""".decode("ASCII") + b"""
>>> len(sa)
3
>>> len(ua)
......@@ -38,7 +38,7 @@ __doc__ = r"""
12
>>> len(null)
1
""".decode(u"ASCII") + u"""
""".decode("ASCII") + u"""
>>> ua == u'abc'
True
>>> b == u'123'
......
......@@ -6,5 +6,5 @@ cdef grail(char *blarg, ...):
pass
def test():
grail("test")
grail("test", "toast")
grail(b"test")
grail(b"test", b"toast")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment