Commit 8d715668 authored by Mark Florisson's avatar Mark Florisson

Merge branch 'master' of https://github.com/cython/cython

parents 5dc75a83 122f3cfb
...@@ -32,3 +32,4 @@ ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1 ...@@ -32,3 +32,4 @@ ef9d2c680684d0df7d81f529cda29e9e1741f575 cython-0.10.1
0000000000000000000000000000000000000000 cython-0.10.1 0000000000000000000000000000000000000000 cython-0.10.1
59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes 59c67af0674bd93c5fd8958e08c76a9dab9aae37 sage-cythonizes
0000000000000000000000000000000000000000 sage-cythonizes 0000000000000000000000000000000000000000 sage-cythonizes
478f57be445d18fe294db849d7ad317fe7d7658f 0.14.alpha0
...@@ -10,6 +10,7 @@ except NameError: ...@@ -10,6 +10,7 @@ except NameError:
from distutils.extension import Extension from distutils.extension import Extension
from Cython import Utils from Cython import Utils
from Cython.Compiler.Main import Context, CompilationOptions, default_options
# Unfortunately, Python 2.3 doesn't support decorators. # Unfortunately, Python 2.3 doesn't support decorators.
def cached_method(f): def cached_method(f):
...@@ -160,23 +161,8 @@ def strip_string_literals(code, prefix='__Pyx_L'): ...@@ -160,23 +161,8 @@ def strip_string_literals(code, prefix='__Pyx_L'):
q = min(single_q, double_q) q = min(single_q, double_q)
if q == -1: q = max(single_q, double_q) if q == -1: q = max(single_q, double_q)
# Process comment.
if -1 < hash_mark and (hash_mark < q or q == -1):
end = code.find('\n', hash_mark)
if end == -1:
end = None
new_code.append(code[start:hash_mark+1])
counter += 1
label = "%s%s" % (prefix, counter)
literals[label] = code[hash_mark+1:end]
new_code.append(label)
if end is None:
break
q = end
start = q
# We're done. # We're done.
elif q == -1: if q == -1 and hash_mark == -1:
new_code.append(code[start:]) new_code.append(code[start:])
break break
...@@ -200,6 +186,21 @@ def strip_string_literals(code, prefix='__Pyx_L'): ...@@ -200,6 +186,21 @@ def strip_string_literals(code, prefix='__Pyx_L'):
else: else:
q += 1 q += 1
# Process comment.
elif -1 != hash_mark and (hash_mark < q or q == -1):
end = code.find('\n', hash_mark)
if end == -1:
end = None
new_code.append(code[start:hash_mark+1])
counter += 1
label = "%s%s" % (prefix, counter)
literals[label] = code[hash_mark+1:end]
new_code.append(label)
if end is None:
break
q = end
start = q
# Open the quote. # Open the quote.
else: else:
raw = False raw = False
...@@ -264,9 +265,15 @@ class DependencyTree(object): ...@@ -264,9 +265,15 @@ class DependencyTree(object):
cimports = set(cimports) cimports = set(cimports)
externs = set(externs) externs = set(externs)
for include in includes: for include in includes:
a, b = self.cimports_and_externs(os.path.join(os.path.dirname(filename), include)) include_path = os.path.join(os.path.dirname(filename), include)
if not os.path.exists(include_path):
include_path = self.context.find_include_file(include, None)
if include_path:
a, b = self.cimports_and_externs(include_path)
cimports.update(a) cimports.update(a)
externs.update(b) externs.update(b)
else:
print "Unable to locate '%s' referenced from '%s'" % (filename, include)
return tuple(cimports), tuple(externs) return tuple(cimports), tuple(externs)
cimports_and_externs = cached_method(cimports_and_externs) cimports_and_externs = cached_method(cimports_and_externs)
...@@ -377,13 +384,11 @@ def create_dependency_tree(ctx=None): ...@@ -377,13 +384,11 @@ def create_dependency_tree(ctx=None):
global _dep_tree global _dep_tree
if _dep_tree is None: if _dep_tree is None:
if ctx is None: if ctx is None:
from Cython.Compiler.Main import Context, CompilationOptions ctx = Context(["."], CompilationOptions(default_options))
ctx = Context(["."], CompilationOptions())
_dep_tree = DependencyTree(ctx) _dep_tree = DependencyTree(ctx)
return _dep_tree return _dep_tree
# TODO: Take common options. # This may be useful for advanced users?
# TODO: Symbolic names (e.g. for numpy.include_dirs()
def create_extension_list(patterns, ctx=None, aliases=None): def create_extension_list(patterns, ctx=None, aliases=None):
seen = set() seen = set()
deps = create_dependency_tree(ctx) deps = create_dependency_tree(ctx)
...@@ -423,7 +428,11 @@ def create_extension_list(patterns, ctx=None, aliases=None): ...@@ -423,7 +428,11 @@ def create_extension_list(patterns, ctx=None, aliases=None):
seen.add(name) seen.add(name)
return module_list return module_list
def cythonize(module_list, ctx=None, nthreads=0, aliases=None): # This is the user-exposed entry point.
def cythonize(module_list, nthreads=0, aliases=None, **options):
c_options = CompilationOptions(**options)
cpp_options = CompilationOptions(**options); cpp_options.cplus = True
ctx = c_options.create_context()
module_list = create_extension_list(module_list, ctx=ctx, aliases=aliases) module_list = create_extension_list(module_list, ctx=ctx, aliases=aliases)
deps = create_dependency_tree(ctx) deps = create_dependency_tree(ctx)
to_compile = [] to_compile = []
...@@ -434,8 +443,10 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None): ...@@ -434,8 +443,10 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None):
if ext in ('.pyx', '.py'): if ext in ('.pyx', '.py'):
if m.language == 'c++': if m.language == 'c++':
c_file = base + '.cpp' c_file = base + '.cpp'
options = cpp_options
else: else:
c_file = base + '.c' c_file = base + '.c'
options = c_options
if os.path.exists(c_file): if os.path.exists(c_file):
c_timestamp = os.path.getmtime(c_file) c_timestamp = os.path.getmtime(c_file)
else: else:
...@@ -450,29 +461,29 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None): ...@@ -450,29 +461,29 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None):
priority = 2 - (dep in deps.immediate_dependencies(source)) priority = 2 - (dep in deps.immediate_dependencies(source))
if c_timestamp < dep_timestamp: if c_timestamp < dep_timestamp:
print("Compiling %s because it depends on %s" % (source, dep)) print("Compiling %s because it depends on %s" % (source, dep))
to_compile.append((priority, source, c_file)) to_compile.append((priority, source, c_file, options))
new_sources.append(c_file) new_sources.append(c_file)
else: else:
new_sources.append(source) new_sources.append(source)
m.sources = new_sources m.sources = new_sources
to_compile.sort() to_compile.sort()
# TODO: invoke directly
if nthreads: if nthreads:
# Requires multiprocessing (or Python >= 2.6) # Requires multiprocessing (or Python >= 2.6)
try: try:
import multiprocessing import multiprocessing
pool = multiprocessing.Pool(nthreads)
pool.map(cythonize_one_helper, to_compile)
except ImportError: except ImportError:
print("multiprocessing required for parallel cythonization") print("multiprocessing required for parallel cythonization")
nthreads = 0 nthreads = 0
pool = multiprocessing.Pool(nthreads)
pool.map(cythonize_one_helper, to_compile)
if not nthreads: if not nthreads:
for priority, pyx_file, c_file in to_compile: for priority, pyx_file, c_file, options in to_compile:
cythonize_one(pyx_file, c_file) cythonize_one(pyx_file, c_file, options)
return module_list return module_list
# TODO: Share context? Issue: pyx processing leaks into pxd module
def cythonize_one(pyx_file, c_file, options=None): def cythonize_one(pyx_file, c_file, options=None):
from Cython.Compiler.Main import compile, CompilationOptions, default_options from Cython.Compiler.Main import compile, default_options
from Cython.Compiler.Errors import CompileError, PyrexError from Cython.Compiler.Errors import CompileError, PyrexError
if options is None: if options is None:
......
...@@ -51,11 +51,12 @@ def unbound_symbols(code, context=None): ...@@ -51,11 +51,12 @@ def unbound_symbols(code, context=None):
unbound.append(name) unbound.append(name)
return unbound return unbound
def get_type(arg, context=None): def get_type(arg, context=None):
py_type = type(arg) py_type = type(arg)
if py_type in [list, tuple, dict, str]: if py_type in [list, tuple, dict, str]:
return py_type.__name__ return py_type.__name__
elif py_type is complex:
return 'double complex'
elif py_type is float: elif py_type is float:
return 'double' return 'double'
elif py_type is bool: elif py_type is bool:
...@@ -75,11 +76,10 @@ def get_type(arg, context=None): ...@@ -75,11 +76,10 @@ def get_type(arg, context=None):
return '%s.%s' % (base_type.__module__, base_type.__name__) return '%s.%s' % (base_type.__module__, base_type.__name__)
return 'object' return 'object'
# TODO: use locals/globals for unbound variables
def cython_inline(code, def cython_inline(code,
types='aggressive', types='aggressive',
lib_dir=os.path.expanduser('~/.cython/inline'), lib_dir=os.path.expanduser('~/.cython/inline'),
include_dirs=['.'], cython_include_dirs=['.'],
locals=None, locals=None,
globals=None, globals=None,
**kwds): **kwds):
...@@ -108,9 +108,6 @@ def cython_inline(code, ...@@ -108,9 +108,6 @@ def cython_inline(code,
arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names]) arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
key = code, arg_sigs, sys.version_info, sys.executable, Cython.__version__ key = code, arg_sigs, sys.version_info, sys.executable, Cython.__version__
module_name = "_cython_inline_" + hashlib.md5(str(key)).hexdigest() module_name = "_cython_inline_" + hashlib.md5(str(key)).hexdigest()
# # TODO: Does this cover all the platforms?
# if (not os.path.exists(os.path.join(lib_dir, module_name + ".so")) and
# not os.path.exists(os.path.join(lib_dir, module_name + ".dll"))):
try: try:
if not os.path.exists(lib_dir): if not os.path.exists(lib_dir):
os.makedirs(lib_dir) os.makedirs(lib_dir)
...@@ -147,7 +144,7 @@ def __invoke(%(params)s): ...@@ -147,7 +144,7 @@ def __invoke(%(params)s):
include_dirs = c_include_dirs) include_dirs = c_include_dirs)
build_extension = build_ext(Distribution()) build_extension = build_ext(Distribution())
build_extension.finalize_options() build_extension.finalize_options()
build_extension.extensions = cythonize([extension]) build_extension.extensions = cythonize([extension], ctx=ctx)
build_extension.build_temp = os.path.dirname(pyx_file) build_extension.build_temp = os.path.dirname(pyx_file)
build_extension.build_lib = lib_dir build_extension.build_lib = lib_dir
build_extension.run() build_extension.run()
......
from Dependencies import cythonize
...@@ -123,7 +123,11 @@ static PyObject* __Pyx_PyRun(PyObject* o, PyObject* globals, PyObject* locals) { ...@@ -123,7 +123,11 @@ static PyObject* __Pyx_PyRun(PyObject* o, PyObject* globals, PyObject* locals) {
"code object passed to exec() may not contain free variables"); "code object passed to exec() may not contain free variables");
goto bad; goto bad;
} }
#if PY_VERSION_HEX < 0x030200A4
result = PyEval_EvalCode((PyCodeObject *)o, globals, locals); result = PyEval_EvalCode((PyCodeObject *)o, globals, locals);
#else
result = PyEval_EvalCode(o, globals, locals);
#endif
} else { } else {
PyCompilerFlags cf; PyCompilerFlags cf;
cf.cf_flags = 0; cf.cf_flags = 0;
...@@ -300,6 +304,22 @@ class _BuiltinOverride(object): ...@@ -300,6 +304,22 @@ class _BuiltinOverride(object):
self.func_type, self.sig = func_type, sig self.func_type, self.sig = func_type, sig
self.utility_code = utility_code self.utility_code = utility_code
class BuiltinAttribute(object):
def __init__(self, py_name, cname=None, field_type=None, field_type_name=None):
self.py_name = py_name
self.cname = cname or py_name
self.field_type_name = field_type_name # can't do the lookup before the type is declared!
self.field_type = field_type
def declare_in_type(self, self_type):
if self.field_type_name is not None:
# lazy type lookup
field_type = builtin_scope.lookup(self.field_type_name).type
else:
field_type = self.field_type or PyrexTypes.py_object_type
entry = self_type.scope.declare(self.py_name, self.cname, field_type, None, 'private')
entry.is_variable = True
class BuiltinFunction(_BuiltinOverride): class BuiltinFunction(_BuiltinOverride):
def declare_in_scope(self, scope): def declare_in_scope(self, scope):
func_type, sig = self.func_type, self.sig func_type, sig = self.func_type, self.sig
...@@ -426,9 +446,10 @@ builtin_types_table = [ ...@@ -426,9 +446,10 @@ builtin_types_table = [
("long", "PyLong_Type", []), ("long", "PyLong_Type", []),
("float", "PyFloat_Type", []), ("float", "PyFloat_Type", []),
# Until we have a way to access attributes of a type, ("complex", "PyComplex_Type", [BuiltinAttribute('cval', field_type_name = 'Py_complex'),
# we don't want to make this one builtin. BuiltinAttribute('real', 'cval.real', field_type = PyrexTypes.c_double_type),
# ("complex", "PyComplex_Type", []), BuiltinAttribute('imag', 'cval.imag', field_type = PyrexTypes.c_double_type),
]),
("bytes", "PyBytes_Type", []), ("bytes", "PyBytes_Type", []),
("str", "PyString_Type", []), ("str", "PyString_Type", []),
...@@ -447,7 +468,10 @@ builtin_types_table = [ ...@@ -447,7 +468,10 @@ builtin_types_table = [
BuiltinMethod("values","T", "O", "PyDict_Values"), # FIXME: Py3 mode? BuiltinMethod("values","T", "O", "PyDict_Values"), # FIXME: Py3 mode?
BuiltinMethod("copy", "T", "T", "PyDict_Copy")]), BuiltinMethod("copy", "T", "T", "PyDict_Copy")]),
("slice", "PySlice_Type", []), ("slice", "PySlice_Type", [BuiltinAttribute('start'),
BuiltinAttribute('stop'),
BuiltinAttribute('step'),
]),
# ("file", "PyFile_Type", []), # not in Py3 # ("file", "PyFile_Type", []), # not in Py3
("set", "PySet_Type", [BuiltinMethod("clear", "T", "i", "PySet_Clear"), ("set", "PySet_Type", [BuiltinMethod("clear", "T", "i", "PySet_Clear"),
...@@ -480,6 +504,10 @@ builtin_structs_table = [ ...@@ -480,6 +504,10 @@ builtin_structs_table = [
("strides", PyrexTypes.c_py_ssize_t_ptr_type), ("strides", PyrexTypes.c_py_ssize_t_ptr_type),
("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type), ("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
("internal", PyrexTypes.c_void_ptr_type), ("internal", PyrexTypes.c_void_ptr_type),
]),
('Py_complex', 'Py_complex',
[('real', PyrexTypes.c_double_type),
('imag', PyrexTypes.c_double_type),
]) ])
] ]
...@@ -497,7 +525,13 @@ def init_builtin_types(): ...@@ -497,7 +525,13 @@ def init_builtin_types():
global builtin_types global builtin_types
for name, cname, methods in builtin_types_table: for name, cname, methods in builtin_types_table:
utility = builtin_utility_code.get(name) utility = builtin_utility_code.get(name)
the_type = builtin_scope.declare_builtin_type(name, cname, utility) if name == 'frozenset':
objstruct_cname = 'PySetObject'
elif name == 'bool':
objstruct_cname = None
else:
objstruct_cname = 'Py%sObject' % name.capitalize()
the_type = builtin_scope.declare_builtin_type(name, cname, utility, objstruct_cname)
builtin_types[name] = the_type builtin_types[name] = the_type
for method in methods: for method in methods:
method.declare_in_type(the_type) method.declare_in_type(the_type)
...@@ -512,9 +546,9 @@ def init_builtin_structs(): ...@@ -512,9 +546,9 @@ def init_builtin_structs():
name, "struct", scope, 1, None, cname = cname) name, "struct", scope, 1, None, cname = cname)
def init_builtins(): def init_builtins():
init_builtin_structs()
init_builtin_funcs() init_builtin_funcs()
init_builtin_types() init_builtin_types()
init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, frozenset_type global list_type, tuple_type, dict_type, set_type, frozenset_type
global bytes_type, str_type, unicode_type global bytes_type, str_type, unicode_type
global float_type, bool_type, type_type, complex_type global float_type, bool_type, type_type, complex_type
......
...@@ -37,6 +37,7 @@ Options: ...@@ -37,6 +37,7 @@ Options:
--embed Embed the Python interpreter in a main() method. --embed Embed the Python interpreter in a main() method.
-2 Compile based on Python-2 syntax and code semantics. -2 Compile based on Python-2 syntax and code semantics.
-3 Compile based on Python-3 syntax and code semantics. -3 Compile based on Python-3 syntax and code semantics.
--fatal-errors Abort the compilation on the first error
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
""" """
...@@ -122,6 +123,8 @@ def parse_command_line(args): ...@@ -122,6 +123,8 @@ def parse_command_line(args):
options.language_level = 2 options.language_level = 2
elif option == '-3': elif option == '-3':
options.language_level = 3 options.language_level = 3
elif option == "--fatal-errors":
Options.fatal_errors = True
elif option in ("-X", "--directive"): elif option in ("-X", "--directive"):
try: try:
options.compiler_directives = Options.parse_directive_list( options.compiler_directives = Options.parse_directive_list(
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import sys import sys
from Cython.Utils import open_new_file from Cython.Utils import open_new_file
from DebugFlags import debug_exception_on_error from DebugFlags import debug_exception_on_error
import Options
class PyrexError(Exception): class PyrexError(Exception):
...@@ -142,6 +143,8 @@ def report_error(err): ...@@ -142,6 +143,8 @@ def report_error(err):
except UnicodeEncodeError: except UnicodeEncodeError:
echo_file.write(line.encode('ASCII', 'replace')) echo_file.write(line.encode('ASCII', 'replace'))
num_errors = num_errors + 1 num_errors = num_errors + 1
if Options.fatal_errors:
raise InternalError, "abort"
def error(position, message): def error(position, message):
#print "Errors.error:", repr(position), repr(message) ### #print "Errors.error:", repr(position), repr(message) ###
......
...@@ -3451,6 +3451,8 @@ class AttributeNode(ExprNode): ...@@ -3451,6 +3451,8 @@ class AttributeNode(ExprNode):
if not target: if not target:
self.is_temp = 1 self.is_temp = 1
self.result_ctype = py_object_type self.result_ctype = py_object_type
elif target and self.obj.type.is_builtin_type:
error(self.pos, "Assignment to an immutable object field")
def analyse_attribute(self, env, obj_type = None): def analyse_attribute(self, env, obj_type = None):
# Look up attribute and set self.type and self.member. # Look up attribute and set self.type and self.member.
...@@ -3466,7 +3468,7 @@ class AttributeNode(ExprNode): ...@@ -3466,7 +3468,7 @@ class AttributeNode(ExprNode):
if obj_type.is_ptr or obj_type.is_array: if obj_type.is_ptr or obj_type.is_array:
obj_type = obj_type.base_type obj_type = obj_type.base_type
self.op = "->" self.op = "->"
elif obj_type.is_extension_type: elif obj_type.is_extension_type or obj_type.is_builtin_type:
self.op = "->" self.op = "->"
else: else:
self.op = "." self.op = "."
...@@ -3558,6 +3560,9 @@ class AttributeNode(ExprNode): ...@@ -3558,6 +3560,9 @@ class AttributeNode(ExprNode):
elif obj.type.is_complex: elif obj.type.is_complex:
return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code) return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
else: else:
if obj.type.is_builtin_type and self.entry and self.entry.is_variable:
# accessing a field of a builtin type, need to cast better than result_as() does
obj_code = obj.type.cast_code(obj.result(), to_object_struct = True)
return "%s%s%s" % (obj_code, self.op, self.member) return "%s%s%s" % (obj_code, self.op, self.member)
def generate_result_code(self, code): def generate_result_code(self, code):
...@@ -4161,6 +4166,54 @@ class ScopedExprNode(ExprNode): ...@@ -4161,6 +4166,54 @@ class ScopedExprNode(ExprNode):
# this is called with the expr_scope as env # this is called with the expr_scope as env
pass pass
def generate_evaluation_code(self, code):
# set up local variables and free their references on exit
generate_inner_evaluation_code = super(ScopedExprNode, self).generate_evaluation_code
if not self.has_local_scope or not self.expr_scope.var_entries:
# no local variables => delegate, done
generate_inner_evaluation_code(code)
return
code.putln('{ /* enter inner scope */')
py_entries = []
for entry in self.expr_scope.var_entries:
if not entry.in_closure:
code.put_var_declaration(entry)
if entry.type.is_pyobject and entry.used:
py_entries.append(entry)
code.put_init_var_to_py_none(entry)
if not py_entries:
# no local Python references => no cleanup required
generate_inner_evaluation_code(code)
code.putln('} /* exit inner scope */')
return
# must free all local Python references at each exit point
old_loop_labels = tuple(code.new_loop_labels())
old_error_label = code.new_error_label()
generate_inner_evaluation_code(code)
# normal (non-error) exit
for entry in py_entries:
code.put_var_decref(entry)
# error/loop body exit points
exit_scope = code.new_label('exit_scope')
code.put_goto(exit_scope)
for label, old_label in ([(code.error_label, old_error_label)] +
list(zip(code.get_loop_labels(), old_loop_labels))):
if code.label_used(label):
code.put_label(label)
for entry in py_entries:
code.put_var_decref(entry)
code.put_goto(old_label)
code.put_label(exit_scope)
code.putln('} /* exit inner scope */')
code.set_loop_labels(old_loop_labels)
code.error_label = old_error_label
class ComprehensionNode(ScopedExprNode): class ComprehensionNode(ScopedExprNode):
subexprs = ["target"] subexprs = ["target"]
...@@ -7021,12 +7074,17 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -7021,12 +7074,17 @@ class CoerceToPyTypeNode(CoercionNode):
if not arg.type.create_to_py_utility_code(env): if not arg.type.create_to_py_utility_code(env):
error(arg.pos, error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type) "Cannot convert '%s' to Python object" % arg.type)
if type is not py_object_type: if type is py_object_type:
self.type = py_object_type # be specific about some known types
elif arg.type.is_string: if arg.type.is_string:
self.type = bytes_type self.type = bytes_type
elif arg.type is PyrexTypes.c_py_unicode_type: elif arg.type is PyrexTypes.c_py_unicode_type:
self.type = unicode_type self.type = unicode_type
elif arg.type.is_complex:
self.type = Builtin.complex_type
else:
# FIXME: check that the target type and the resulting type are compatible
pass
gil_message = "Converting to Python object" gil_message = "Converting to Python object"
......
...@@ -577,8 +577,7 @@ def create_default_resultobj(compilation_source, options): ...@@ -577,8 +577,7 @@ def create_default_resultobj(compilation_source, options):
def run_pipeline(source, options, full_module_name = None): def run_pipeline(source, options, full_module_name = None):
# Set up context # Set up context
context = Context(options.include_path, options.compiler_directives, context = options.create_context()
options.cplus, options.language_level)
# Set up source object # Set up source object
cwd = os.getcwd() cwd = os.getcwd()
...@@ -649,6 +648,10 @@ class CompilationOptions(object): ...@@ -649,6 +648,10 @@ class CompilationOptions(object):
self.__dict__.update(defaults) self.__dict__.update(defaults)
self.__dict__.update(kw) self.__dict__.update(kw)
def create_context(self):
return Context(self.include_path, self.compiler_directives,
self.cplus, self.language_level)
class CompilationResult(object): class CompilationResult(object):
""" """
......
...@@ -271,9 +271,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -271,9 +271,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code = globalstate['all_the_rest'] code = globalstate['all_the_rest']
self.generate_cached_builtins_decls(env, code) self.generate_cached_builtins_decls(env, code)
# generate lambda function definitions self.generate_lambda_definitions(env, code)
for node in env.lambda_defs:
node.generate_function_definitions(env, code)
# generate normal function definitions # generate normal function definitions
self.body.generate_function_definitions(env, code) self.body.generate_function_definitions(env, code)
code.mark_pos(None) code.mark_pos(None)
...@@ -2020,7 +2018,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2020,7 +2018,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_base_type_import_code(self, env, entry, code): def generate_base_type_import_code(self, env, entry, code):
base_type = entry.type.base_type base_type = entry.type.base_type
if base_type and base_type.module_name != env.qualified_name: if base_type and base_type.module_name != env.qualified_name \
and not base_type.is_builtin_type:
self.generate_type_import_code(env, base_type, self.pos, code) self.generate_type_import_code(env, base_type, self.pos, code)
def use_type_import_utility_code(self, env): def use_type_import_utility_code(self, env):
...@@ -2098,7 +2097,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2098,7 +2097,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# unless we let PyType_Ready create the slot wrappers we have # unless we let PyType_Ready create the slot wrappers we have
# a significant performance hit. (See trac #561.) # a significant performance hit. (See trac #561.)
for func in entry.type.scope.pyfunc_entries: for func in entry.type.scope.pyfunc_entries:
if func.is_special and func.wrapperbase_cname: if func.is_special and Options.docstrings and func.wrapperbase_cname:
code.putln("{"); code.putln("{");
code.putln( code.putln(
'PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&%s, "%s"); %s' % ( 'PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&%s, "%s"); %s' % (
......
...@@ -322,6 +322,9 @@ class BlockNode(object): ...@@ -322,6 +322,9 @@ class BlockNode(object):
code.globalstate.add_cached_builtin_decl(entry) code.globalstate.add_cached_builtin_decl(entry)
del entries[:] del entries[:]
def generate_lambda_definitions(self, env, code):
for node in env.lambda_defs:
node.generate_function_definitions(env, code)
class StatListNode(Node): class StatListNode(Node):
# stats a list of StatNode # stats a list of StatNode
...@@ -783,6 +786,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -783,6 +786,14 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
error(self.pos, "can only complexify c numeric types") error(self.pos, "can only complexify c numeric types")
type = PyrexTypes.CComplexType(type) type = PyrexTypes.CComplexType(type)
type.create_declaration_utility_code(env) type.create_declaration_utility_code(env)
elif type is Builtin.complex_type:
# Special case: optimise builtin complex type into C's
# double complex. The parser cannot do this (as for the
# normal scalar types) as the user may have redeclared the
# 'complex' type. Testing for the exact type here works.
type = PyrexTypes.c_double_complex_type
type.create_declaration_utility_code(env)
self.complex = True
if type: if type:
return type return type
else: else:
...@@ -1211,8 +1222,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1211,8 +1222,7 @@ class FuncDefNode(StatNode, BlockNode):
# Generate closure function definitions # Generate closure function definitions
self.body.generate_function_definitions(lenv, code) self.body.generate_function_definitions(lenv, code)
# generate lambda function definitions # generate lambda function definitions
for node in lenv.lambda_defs: self.generate_lambda_definitions(lenv, code)
node.generate_function_definitions(lenv, code)
is_getbuffer_slot = (self.entry.name == "__getbuffer__" and is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
self.entry.scope.is_c_class_scope) self.entry.scope.is_c_class_scope)
...@@ -3079,6 +3089,7 @@ class PyClassDefNode(ClassDefNode): ...@@ -3079,6 +3089,7 @@ class PyClassDefNode(ClassDefNode):
self.target.analyse_target_expression(env, self.classobj) self.target.analyse_target_expression(env, self.classobj)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.generate_lambda_definitions(self.scope, code)
self.body.generate_function_definitions(self.scope, code) self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code): def generate_execution_code(self, code):
...@@ -3181,7 +3192,9 @@ class CClassDefNode(ClassDefNode): ...@@ -3181,7 +3192,9 @@ class CClassDefNode(ClassDefNode):
if base_class_entry: if base_class_entry:
if not base_class_entry.is_type: if not base_class_entry.is_type:
error(self.pos, "'%s' is not a type name" % self.base_class_name) error(self.pos, "'%s' is not a type name" % self.base_class_name)
elif not base_class_entry.type.is_extension_type: elif not base_class_entry.type.is_extension_type and \
not (base_class_entry.type.is_builtin_type and \
base_class_entry.type.objstruct_cname):
error(self.pos, "'%s' is not an extension type" % self.base_class_name) error(self.pos, "'%s' is not an extension type" % self.base_class_name)
elif not base_class_entry.type.is_complete(): elif not base_class_entry.type.is_complete():
error(self.pos, "Base class '%s' of type '%s' is incomplete" % ( error(self.pos, "Base class '%s' of type '%s' is incomplete" % (
...@@ -3190,6 +3203,10 @@ class CClassDefNode(ClassDefNode): ...@@ -3190,6 +3203,10 @@ class CClassDefNode(ClassDefNode):
base_class_entry.type.scope.directives['final']: base_class_entry.type.scope.directives['final']:
error(self.pos, "Base class '%s' of type '%s' is final" % ( error(self.pos, "Base class '%s' of type '%s' is final" % (
self.base_class_name, self.class_name)) self.base_class_name, self.class_name))
elif base_class_entry.type.is_builtin_type and \
base_class_entry.type.name in ('tuple', 'str', 'bytes'):
error(self.pos, "inheritance from PyVarObject types like '%s' is not currently supported"
% base_class_entry.type.name)
else: else:
self.base_type = base_class_entry.type self.base_type = base_class_entry.type
has_body = self.body is not None has_body = self.body is not None
...@@ -3242,8 +3259,8 @@ class CClassDefNode(ClassDefNode): ...@@ -3242,8 +3259,8 @@ class CClassDefNode(ClassDefNode):
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
if self.body: if self.body:
self.body.generate_function_definitions( self.generate_lambda_definitions(self.scope, code)
self.entry.type.scope, code) self.body.generate_function_definitions(self.scope, code)
def generate_execution_code(self, code): def generate_execution_code(self, code):
# This is needed to generate evaluation code for # This is needed to generate evaluation code for
......
...@@ -18,6 +18,10 @@ generate_cleanup_code = 0 ...@@ -18,6 +18,10 @@ generate_cleanup_code = 0
annotate = 0 annotate = 0
# This will abort the compilation on the first error occured rather than trying
# to keep going and printing further error messages.
fatal_errors = False
# This will convert statements of the form "for i in range(...)" # This will convert statements of the form "for i in range(...)"
# to "for i from ..." when i is a cdef'd integer type, and the direction # to "for i from ..." when i is a cdef'd integer type, and the direction
# (i.e. sign of step) can be determined. # (i.e. sign of step) can be determined.
......
import cython import cython
cython.declare(copy=object, ModuleNode=object, TreeFragment=object, TemplateTransform=object, cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
EncodedString=object, error=object, warning=object, PyrexTypes=object, Naming=object) Options=object, UtilNodes=object, ModuleNode=object,
LetNode=object, LetRefNode=object, TreeFragment=object,
TemplateTransform=object, EncodedString=object,
error=object, warning=object, copy=object)
import PyrexTypes
import Naming
import ExprNodes
import Nodes
import Options
from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
from Cython.Compiler.ModuleNode import ModuleNode from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import * from Cython.Compiler.UtilNodes import LetNode, LetRefNode
from Cython.Compiler.ExprNodes import *
from Cython.Compiler.UtilNodes import *
from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
from Cython.Compiler.StringEncoding import EncodedString from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import error, warning, CompileError from Cython.Compiler.Errors import error, warning, CompileError, InternalError
from Cython.Compiler import PyrexTypes, Naming
try: try:
...@@ -104,7 +110,7 @@ class NormalizeTree(CythonTransform): ...@@ -104,7 +110,7 @@ class NormalizeTree(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
self.is_in_statlist = stacktmp self.is_in_statlist = stacktmp
if not self.is_in_statlist and not self.is_in_expr: if not self.is_in_statlist and not self.is_in_expr:
return StatListNode(pos=node.pos, stats=[node]) return Nodes.StatListNode(pos=node.pos, stats=[node])
else: else:
return node return node
...@@ -126,7 +132,7 @@ class NormalizeTree(CythonTransform): ...@@ -126,7 +132,7 @@ class NormalizeTree(CythonTransform):
# Eliminate PassStatNode # Eliminate PassStatNode
def visit_PassStatNode(self, node): def visit_PassStatNode(self, node):
if not self.is_in_statlist: if not self.is_in_statlist:
return StatListNode(pos=node.pos, stats=[]) return Nodes.StatListNode(pos=node.pos, stats=[])
else: else:
return [] return []
...@@ -203,7 +209,7 @@ class PostParse(ScopeTrackingTransform): ...@@ -203,7 +209,7 @@ class PostParse(ScopeTrackingTransform):
# cdef variables # cdef variables
def handle_bufferdefaults(self, decl): def handle_bufferdefaults(self, decl):
if not isinstance(decl.default, DictNode): if not isinstance(decl.default, ExprNodes.DictNode):
raise PostParseError(decl.pos, ERR_BUF_DEFAULTS) raise PostParseError(decl.pos, ERR_BUF_DEFAULTS)
self.scope_node.buffer_defaults_node = decl.default self.scope_node.buffer_defaults_node = decl.default
self.scope_node.buffer_defaults_pos = decl.pos self.scope_node.buffer_defaults_pos = decl.pos
...@@ -219,12 +225,12 @@ class PostParse(ScopeTrackingTransform): ...@@ -219,12 +225,12 @@ class PostParse(ScopeTrackingTransform):
newdecls = [] newdecls = []
for decl in node.declarators: for decl in node.declarators:
declbase = decl declbase = decl
while isinstance(declbase, CPtrDeclaratorNode): while isinstance(declbase, Nodes.CPtrDeclaratorNode):
declbase = declbase.base declbase = declbase.base
if isinstance(declbase, CNameDeclaratorNode): if isinstance(declbase, Nodes.CNameDeclaratorNode):
if declbase.default is not None: if declbase.default is not None:
if self.scope_type in ('cclass', 'pyclass', 'struct'): if self.scope_type in ('cclass', 'pyclass', 'struct'):
if isinstance(self.scope_node, CClassDefNode): if isinstance(self.scope_node, Nodes.CClassDefNode):
handler = self.specialattribute_handlers.get(decl.name) handler = self.specialattribute_handlers.get(decl.name)
if handler: if handler:
if decl is not declbase: if decl is not declbase:
...@@ -233,8 +239,8 @@ class PostParse(ScopeTrackingTransform): ...@@ -233,8 +239,8 @@ class PostParse(ScopeTrackingTransform):
continue # Remove declaration continue # Remove declaration
raise PostParseError(decl.pos, ERR_CDEF_INCLASS) raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
first_assignment = self.scope_type != 'module' first_assignment = self.scope_type != 'module'
stats.append(SingleAssignmentNode(node.pos, stats.append(Nodes.SingleAssignmentNode(node.pos,
lhs=NameNode(node.pos, name=declbase.name), lhs=ExprNodes.NameNode(node.pos, name=declbase.name),
rhs=declbase.default, first=first_assignment)) rhs=declbase.default, first=first_assignment))
declbase.default = None declbase.default = None
newdecls.append(decl) newdecls.append(decl)
...@@ -511,11 +517,11 @@ class PxdPostParse(CythonTransform, SkipDeclarations): ...@@ -511,11 +517,11 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
# an imp they are CVarDefNodes..) # an imp they are CVarDefNodes..)
err = self.ERR_INLINE_ONLY err = self.ERR_INLINE_ONLY
if (isinstance(node, DefNode) and self.scope_type == 'cclass' if (isinstance(node, Nodes.DefNode) and self.scope_type == 'cclass'
and node.name in ('__getbuffer__', '__releasebuffer__')): and node.name in ('__getbuffer__', '__releasebuffer__')):
err = None # allow these slots err = None # allow these slots
if isinstance(node, CFuncDefNode): if isinstance(node, Nodes.CFuncDefNode):
if u'inline' in node.modifiers and self.scope_type == 'pxd': if u'inline' in node.modifiers and self.scope_type == 'pxd':
node.inline_in_pxd = True node.inline_in_pxd = True
if node.visibility != 'private': if node.visibility != 'private':
...@@ -560,21 +566,21 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -560,21 +566,21 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
and which names the "cython" module may have been imported to. and which names the "cython" module may have been imported to.
""" """
unop_method_nodes = { unop_method_nodes = {
'typeof': TypeofNode, 'typeof': ExprNodes.TypeofNode,
'operator.address': AmpersandNode, 'operator.address': ExprNodes.AmpersandNode,
'operator.dereference': DereferenceNode, 'operator.dereference': ExprNodes.DereferenceNode,
'operator.preincrement' : inc_dec_constructor(True, '++'), 'operator.preincrement' : ExprNodes.inc_dec_constructor(True, '++'),
'operator.predecrement' : inc_dec_constructor(True, '--'), 'operator.predecrement' : ExprNodes.inc_dec_constructor(True, '--'),
'operator.postincrement': inc_dec_constructor(False, '++'), 'operator.postincrement': ExprNodes.inc_dec_constructor(False, '++'),
'operator.postdecrement': inc_dec_constructor(False, '--'), 'operator.postdecrement': ExprNodes.inc_dec_constructor(False, '--'),
# For backwards compatability. # For backwards compatability.
'address': AmpersandNode, 'address': ExprNodes.AmpersandNode,
} }
binop_method_nodes = { binop_method_nodes = {
'operator.comma' : c_binop_constructor(','), 'operator.comma' : ExprNodes.c_binop_constructor(','),
} }
special_methods = cython.set(['declare', 'union', 'struct', 'typedef', 'sizeof', special_methods = cython.set(['declare', 'union', 'struct', 'typedef', 'sizeof',
...@@ -672,9 +678,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -672,9 +678,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return node return node
def visit_SingleAssignmentNode(self, node): def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ImportNode) and if (isinstance(node.rhs, ExprNodes.ImportNode) and
node.rhs.module_name.value == u'cython'): node.rhs.module_name.value == u'cython'):
node = CImportStatNode(node.pos, node = Nodes.CImportStatNode(node.pos,
module_name = u'cython', module_name = u'cython',
as_name = node.lhs.name) as_name = node.lhs.name)
self.visit_CImportStatNode(node) self.visit_CImportStatNode(node)
...@@ -693,7 +699,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -693,7 +699,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# If node is the contents of an directive (in a with statement or # If node is the contents of an directive (in a with statement or
# decorator), returns a list of (directivename, value) pairs. # decorator), returns a list of (directivename, value) pairs.
# Otherwise, returns None # Otherwise, returns None
if isinstance(node, CallNode): if isinstance(node, ExprNodes.CallNode):
self.visit(node.function) self.visit(node.function)
optname = node.function.as_cython_attribute() optname = node.function.as_cython_attribute()
if optname: if optname:
...@@ -718,7 +724,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -718,7 +724,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return directives return directives
directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos)) directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
return directives return directives
elif isinstance(node, (AttributeNode, NameNode)): elif isinstance(node, (ExprNodes.AttributeNode, ExprNodes.NameNode)):
self.visit(node) self.visit(node)
optname = node.as_cython_attribute() optname = node.as_cython_attribute()
if optname: if optname:
...@@ -734,15 +740,16 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -734,15 +740,16 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
def try_to_parse_directive(self, optname, args, kwds, pos): def try_to_parse_directive(self, optname, args, kwds, pos):
directivetype = Options.directive_types.get(optname) directivetype = Options.directive_types.get(optname)
if len(args) == 1 and isinstance(args[0], NoneNode): if len(args) == 1 and isinstance(args[0], ExprNodes.NoneNode):
return optname, Options.directive_defaults[optname] return optname, Options.directive_defaults[optname]
elif directivetype is bool: elif directivetype is bool:
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode): if kwds is not None or len(args) != 1 or not isinstance(args[0], ExprNodes.BoolNode):
raise PostParseError(pos, raise PostParseError(pos,
'The %s directive takes one compile-time boolean argument' % optname) 'The %s directive takes one compile-time boolean argument' % optname)
return (optname, args[0].value) return (optname, args[0].value)
elif directivetype is str: elif directivetype is str:
if kwds is not None or len(args) != 1 or not isinstance(args[0], (StringNode, UnicodeNode)): if kwds is not None or len(args) != 1 or not isinstance(args[0], (ExprNodes.StringNode,
ExprNodes.UnicodeNode)):
raise PostParseError(pos, raise PostParseError(pos,
'The %s directive takes one compile-time string argument' % optname) 'The %s directive takes one compile-time string argument' % optname)
return (optname, str(args[0].value)) return (optname, str(args[0].value))
...@@ -764,9 +771,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -764,9 +771,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
newdirectives = copy.copy(olddirectives) newdirectives = copy.copy(olddirectives)
newdirectives.update(directives) newdirectives.update(directives)
self.directives = newdirectives self.directives = newdirectives
assert isinstance(body, StatListNode), body assert isinstance(body, Nodes.StatListNode), body
retbody = self.visit_Node(body) retbody = self.visit_Node(body)
directive = CompilerDirectivesNode(pos=retbody.pos, body=retbody, directive = Nodes.CompilerDirectivesNode(pos=retbody.pos, body=retbody,
directives=newdirectives) directives=newdirectives)
self.directives = olddirectives self.directives = olddirectives
return directive return directive
...@@ -776,7 +783,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -776,7 +783,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
directives = self._extract_directives(node, 'function') directives = self._extract_directives(node, 'function')
if not directives: if not directives:
return self.visit_Node(node) return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node]) body = Nodes.StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives) return self.visit_with_directives(body, directives)
def visit_CVarDefNode(self, node): def visit_CVarDefNode(self, node):
...@@ -795,14 +802,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -795,14 +802,14 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
directives = self._extract_directives(node, 'cclass') directives = self._extract_directives(node, 'cclass')
if not directives: if not directives:
return self.visit_Node(node) return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node]) body = Nodes.StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives) return self.visit_with_directives(body, directives)
def visit_PyClassDefNode(self, node): def visit_PyClassDefNode(self, node):
directives = self._extract_directives(node, 'class') directives = self._extract_directives(node, 'class')
if not directives: if not directives:
return self.visit_Node(node) return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node]) body = Nodes.StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives) return self.visit_with_directives(body, directives)
def _extract_directives(self, node, scope_name): def _extract_directives(self, node, scope_name):
...@@ -819,7 +826,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -819,7 +826,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
directives.append(directive) directives.append(directive)
else: else:
realdecs.append(dec) realdecs.append(dec)
if realdecs and isinstance(node, (CFuncDefNode, CClassDefNode)): if realdecs and isinstance(node, (Nodes.CFuncDefNode, Nodes.CClassDefNode)):
raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.") raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.")
else: else:
node.decorators = realdecs node.decorators = realdecs
...@@ -854,7 +861,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): ...@@ -854,7 +861,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
name, value = directive name, value = directive
if name == 'nogil': if name == 'nogil':
# special case: in pure mode, "with nogil" spells "with cython.nogil" # special case: in pure mode, "with nogil" spells "with cython.nogil"
node = GILStatNode(node.pos, state = "nogil", body = node.body) node = Nodes.GILStatNode(node.pos, state = "nogil", body = node.body)
return self.visit_Node(node) return self.visit_Node(node)
if self.check_directive_scope(node.pos, name, 'with statement'): if self.check_directive_scope(node.pos, name, 'with statement'):
directive_dict[name] = value directive_dict[name] = value
...@@ -914,7 +921,7 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -914,7 +921,7 @@ class WithTransform(CythonTransform, SkipDeclarations):
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
self.visitchildren(node, ['body']) self.visitchildren(node, ['body'])
excinfo_temp = NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type) excinfo_temp = ExprNodes.NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
if node.target is not None: if node.target is not None:
result = self.template_with_target.substitute({ result = self.template_with_target.substitute({
u'EXPR' : node.manager, u'EXPR' : node.manager,
...@@ -931,7 +938,7 @@ class WithTransform(CythonTransform, SkipDeclarations): ...@@ -931,7 +938,7 @@ class WithTransform(CythonTransform, SkipDeclarations):
# Set except excinfo target to EXCINFO # Set except excinfo target to EXCINFO
try_except = result.stats[-1].body.stats[-1] try_except = result.stats[-1].body.stats[-1]
try_except.except_clauses[0].excinfo_target = NameNode(node.pos, name=handle) try_except.except_clauses[0].excinfo_target = ExprNodes.NameNode(node.pos, name=handle)
# excinfo_temp.ref(node.pos)) # excinfo_temp.ref(node.pos))
# result.stats[-1].body.stats[-1] = TempsBlockNode( # result.stats[-1].body.stats[-1] = TempsBlockNode(
...@@ -978,15 +985,15 @@ class DecoratorTransform(CythonTransform, SkipDeclarations): ...@@ -978,15 +985,15 @@ class DecoratorTransform(CythonTransform, SkipDeclarations):
class_node, class_node.name) class_node, class_node.name)
def _handle_decorators(self, node, name): def _handle_decorators(self, node, name):
decorator_result = NameNode(node.pos, name = name) decorator_result = ExprNodes.NameNode(node.pos, name = name)
for decorator in node.decorators[::-1]: for decorator in node.decorators[::-1]:
decorator_result = SimpleCallNode( decorator_result = ExprNodes.SimpleCallNode(
decorator.pos, decorator.pos,
function = decorator.decorator, function = decorator.decorator,
args = [decorator_result]) args = [decorator_result])
name_node = NameNode(node.pos, name = name) name_node = ExprNodes.NameNode(node.pos, name = name)
reassignment = SingleAssignmentNode( reassignment = Nodes.SingleAssignmentNode(
node.pos, node.pos,
lhs = name_node, lhs = name_node,
rhs = decorator_result) rhs = decorator_result)
...@@ -1145,8 +1152,8 @@ property NAME: ...@@ -1145,8 +1152,8 @@ property NAME:
elif entry.visibility == 'readonly': elif entry.visibility == 'readonly':
template = self.basic_property_ro template = self.basic_property_ro
property = template.substitute({ property = template.substitute({
u"ATTR": AttributeNode(pos=entry.pos, u"ATTR": ExprNodes.AttributeNode(pos=entry.pos,
obj=NameNode(pos=entry.pos, name="self"), obj=ExprNodes.NameNode(pos=entry.pos, name="self"),
attribute=entry.name), attribute=entry.name),
}, pos=entry.pos).stats[0] }, pos=entry.pos).stats[0]
property.name = entry.name property.name = entry.name
...@@ -1200,26 +1207,26 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1200,26 +1207,26 @@ class ExpandInplaceOperators(EnvTransform):
if lhs.type.is_cpp_class: if lhs.type.is_cpp_class:
# No getting around this exact operator here. # No getting around this exact operator here.
return node return node
if isinstance(lhs, IndexNode) and lhs.is_buffer_access: if isinstance(lhs, ExprNodes.IndexNode) and lhs.is_buffer_access:
# There is code to handle this case. # There is code to handle this case.
return node return node
env = self.current_env() env = self.current_env()
def side_effect_free_reference(node, setting=False): def side_effect_free_reference(node, setting=False):
if isinstance(node, NameNode): if isinstance(node, ExprNodes.NameNode):
return node, [] return node, []
elif node.type.is_pyobject and not setting: elif node.type.is_pyobject and not setting:
node = LetRefNode(node) node = LetRefNode(node)
return node, [node] return node, [node]
elif isinstance(node, IndexNode): elif isinstance(node, ExprNodes.IndexNode):
if node.is_buffer_access: if node.is_buffer_access:
raise ValueError, "Buffer access" raise ValueError, "Buffer access"
base, temps = side_effect_free_reference(node.base) base, temps = side_effect_free_reference(node.base)
index = LetRefNode(node.index) index = LetRefNode(node.index)
return IndexNode(node.pos, base=base, index=index), temps + [index] return ExprNodes.IndexNode(node.pos, base=base, index=index), temps + [index]
elif isinstance(node, AttributeNode): elif isinstance(node, ExprNodes.AttributeNode):
obj, temps = side_effect_free_reference(node.obj) obj, temps = side_effect_free_reference(node.obj)
return AttributeNode(node.pos, obj=obj, attribute=node.attribute), temps return ExprNodes.AttributeNode(node.pos, obj=obj, attribute=node.attribute), temps
else: else:
node = LetRefNode(node) node = LetRefNode(node)
return node, [node] return node, [node]
...@@ -1228,7 +1235,7 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1228,7 +1235,7 @@ class ExpandInplaceOperators(EnvTransform):
except ValueError: except ValueError:
return node return node
dup = lhs.__class__(**lhs.__dict__) dup = lhs.__class__(**lhs.__dict__)
binop = binop_node(node.pos, binop = ExprNodes.binop_node(node.pos,
operator = node.operator, operator = node.operator,
operand1 = dup, operand1 = dup,
operand2 = rhs, operand2 = rhs,
...@@ -1237,7 +1244,7 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1237,7 +1244,7 @@ class ExpandInplaceOperators(EnvTransform):
lhs.analyse_target_types(env) lhs.analyse_target_types(env)
dup.analyse_types(env) dup.analyse_types(env)
binop.analyse_operation(env) binop.analyse_operation(env)
node = SingleAssignmentNode( node = Nodes.SingleAssignmentNode(
node.pos, node.pos,
lhs = lhs, lhs = lhs,
rhs=binop.coerce_to(lhs.type, env)) rhs=binop.coerce_to(lhs.type, env))
...@@ -1493,11 +1500,11 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1493,11 +1500,11 @@ class TransformBuiltinMethods(EnvTransform):
attribute = node.as_cython_attribute() attribute = node.as_cython_attribute()
if attribute: if attribute:
if attribute == u'compiled': if attribute == u'compiled':
node = BoolNode(node.pos, value=True) node = ExprNodes.BoolNode(node.pos, value=True)
elif attribute == u'NULL': elif attribute == u'NULL':
node = NullNode(node.pos) node = ExprNodes.NullNode(node.pos)
elif attribute in (u'set', u'frozenset'): elif attribute in (u'set', u'frozenset'):
node = NameNode(node.pos, name=EncodedString(attribute), node = ExprNodes.NameNode(node.pos, name=EncodedString(attribute),
entry=self.current_env().builtin_scope().lookup_here(attribute)) entry=self.current_env().builtin_scope().lookup_here(attribute))
elif not PyrexTypes.parse_basic_type(attribute): elif not PyrexTypes.parse_basic_type(attribute):
error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute) error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
...@@ -1542,7 +1549,7 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1542,7 +1549,7 @@ class TransformBuiltinMethods(EnvTransform):
else: else:
type = node.args[0].analyse_as_type(self.current_env()) type = node.args[0].analyse_as_type(self.current_env())
if type: if type:
node = TypecastNode(node.function.pos, type=type, operand=node.args[1]) node = ExprNodes.TypecastNode(node.function.pos, type=type, operand=node.args[1])
else: else:
error(node.args[0].pos, "Not a type") error(node.args[0].pos, "Not a type")
elif function == u'sizeof': elif function == u'sizeof':
...@@ -1551,23 +1558,23 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -1551,23 +1558,23 @@ class TransformBuiltinMethods(EnvTransform):
else: else:
type = node.args[0].analyse_as_type(self.current_env()) type = node.args[0].analyse_as_type(self.current_env())
if type: if type:
node = SizeofTypeNode(node.function.pos, arg_type=type) node = ExprNodes.SizeofTypeNode(node.function.pos, arg_type=type)
else: else:
node = SizeofVarNode(node.function.pos, operand=node.args[0]) node = ExprNodes.SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'cmod': elif function == 'cmod':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cmod() takes exactly two arguments") error(node.function.pos, u"cmod() takes exactly two arguments")
else: else:
node = binop_node(node.function.pos, '%', node.args[0], node.args[1]) node = ExprNodes.binop_node(node.function.pos, '%', node.args[0], node.args[1])
node.cdivision = True node.cdivision = True
elif function == 'cdiv': elif function == 'cdiv':
if len(node.args) != 2: if len(node.args) != 2:
error(node.function.pos, u"cdiv() takes exactly two arguments") error(node.function.pos, u"cdiv() takes exactly two arguments")
else: else:
node = binop_node(node.function.pos, '/', node.args[0], node.args[1]) node = ExprNodes.binop_node(node.function.pos, '/', node.args[0], node.args[1])
node.cdivision = True node.cdivision = True
elif function == u'set': elif function == u'set':
node.function = NameNode(node.pos, name=EncodedString('set')) node.function = ExprNodes.NameNode(node.pos, name=EncodedString('set'))
else: else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function) error(node.function.pos, u"'%s' not a valid cython language construct" % function)
......
...@@ -1913,7 +1913,7 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None): ...@@ -1913,7 +1913,7 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
name = s.systring name = s.systring
s.next() s.next()
else: else:
name = 'int' name = 'int' # long [int], short [int], long [int] complex, etc.
if s.sy == 'IDENT' and s.systring == 'complex': if s.sy == 'IDENT' and s.systring == 'complex':
complex = 1 complex = 1
s.next() s.next()
......
...@@ -373,16 +373,25 @@ class PyObjectType(PyrexType): ...@@ -373,16 +373,25 @@ class PyObjectType(PyrexType):
return cname return cname
class BuiltinObjectType(PyObjectType): class BuiltinObjectType(PyObjectType):
# objstruct_cname string Name of PyObject struct
is_builtin_type = 1 is_builtin_type = 1
has_attributes = 1 has_attributes = 1
base_type = None base_type = None
module_name = '__builtin__' module_name = '__builtin__'
def __init__(self, name, cname): # fields that let it look like an extension type
vtabslot_cname = None
vtabstruct_cname = None
vtabptr_cname = None
typedef_flag = True
is_external = True
def __init__(self, name, cname, objstruct_cname=None):
self.name = name self.name = name
self.cname = cname self.cname = cname
self.typeptr_cname = "&" + cname self.typeptr_cname = "(&%s)" % cname
self.objstruct_cname = objstruct_cname
def set_scope(self, scope): def set_scope(self, scope):
self.scope = scope self.scope = scope
...@@ -415,16 +424,13 @@ class BuiltinObjectType(PyObjectType): ...@@ -415,16 +424,13 @@ class BuiltinObjectType(PyObjectType):
def type_check_function(self, exact=True): def type_check_function(self, exact=True):
type_name = self.name type_name = self.name
if type_name == 'bool':
return 'PyBool_Check'
if type_name == 'str': if type_name == 'str':
type_check = 'PyString_Check' type_check = 'PyString_Check'
elif type_name == 'frozenset': elif type_name == 'frozenset':
type_check = 'PyFrozenSet_Check' type_check = 'PyFrozenSet_Check'
else: else:
type_check = 'Py%s_Check' % type_name.capitalize() type_check = 'Py%s_Check' % type_name.capitalize()
if exact: if exact and type_name not in ('bool', 'slice'):
type_check += 'Exact' type_check += 'Exact'
return type_check return type_check
...@@ -448,6 +454,11 @@ class BuiltinObjectType(PyObjectType): ...@@ -448,6 +454,11 @@ class BuiltinObjectType(PyObjectType):
entity_code = "*%s" % entity_code entity_code = "*%s" % entity_code
return self.base_declaration_code(base_code, entity_code) return self.base_declaration_code(base_code, entity_code)
def cast_code(self, expr_code, to_object_struct = False):
return "((%s*)%s)" % (
to_object_struct and self.objstruct_cname or "PyObject", # self.objstruct_cname may be None
expr_code)
class PyExtensionType(PyObjectType): class PyExtensionType(PyObjectType):
# #
...@@ -2314,7 +2325,7 @@ modifiers_and_name_to_type = { ...@@ -2314,7 +2325,7 @@ modifiers_and_name_to_type = {
(1, 0, "double"): c_double_type, (1, 0, "double"): c_double_type,
(1, 1, "double"): c_longdouble_type, (1, 1, "double"): c_longdouble_type,
(1, 0, "complex"): c_float_complex_type, (1, 0, "complex"): c_double_complex_type, # C: float, Python: double => Python wins
(1, 0, "floatcomplex"): c_float_complex_type, (1, 0, "floatcomplex"): c_float_complex_type,
(1, 0, "doublecomplex"): c_double_complex_type, (1, 0, "doublecomplex"): c_double_complex_type,
(1, 1, "doublecomplex"): c_longdouble_complex_type, (1, 1, "doublecomplex"): c_longdouble_complex_type,
......
...@@ -741,9 +741,9 @@ class BuiltinScope(Scope): ...@@ -741,9 +741,9 @@ class BuiltinScope(Scope):
entry.as_variable = var_entry entry.as_variable = var_entry
return entry return entry
def declare_builtin_type(self, name, cname, utility_code = None): def declare_builtin_type(self, name, cname, utility_code = None, objstruct_cname = None):
name = EncodedString(name) name = EncodedString(name)
type = PyrexTypes.BuiltinObjectType(name, cname) type = PyrexTypes.BuiltinObjectType(name, cname, objstruct_cname)
scope = CClassScope(name, outer_scope=None, visibility='extern') scope = CClassScope(name, outer_scope=None, visibility='extern')
scope.directives = {} scope.directives = {}
if name == 'bool': if name == 'bool':
...@@ -1313,7 +1313,9 @@ class GeneratorExpressionScope(Scope): ...@@ -1313,7 +1313,9 @@ class GeneratorExpressionScope(Scope):
# the parent scope needs to generate code for the variable, but # the parent scope needs to generate code for the variable, but
# this scope must hold its name exclusively # this scope must hold its name exclusively
cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name)) cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name))
entry = self.parent_scope.declare_var(None, type, pos, cname, visibility, is_cdef = True) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
self.var_entries.append(entry)
self.entries[name] = entry self.entries[name] = entry
return entry return entry
......
...@@ -105,7 +105,7 @@ class TreeVisitor(object): ...@@ -105,7 +105,7 @@ class TreeVisitor(object):
code = frame.f_code code = frame.f_code
method_name = code.co_name method_name = code.co_name
pos = (os.path.basename(code.co_filename), pos = (os.path.basename(code.co_filename),
code.co_firstlineno) frame.f_lineno)
nodes.append((node, method_name, pos)) nodes.append((node, method_name, pos))
last_traceback = stacktrace last_traceback = stacktrace
stacktrace = stacktrace.tb_next stacktrace = stacktrace.tb_next
......
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef struct Py_complex
ctypedef struct Py_complex:
double imag
double real
############################################################################ ############################################################################
# 7.2.5.2 Complex Numbers as Python Objects # 7.2.5.2 Complex Numbers as Python Objects
...@@ -9,6 +12,12 @@ cdef extern from "Python.h": ...@@ -9,6 +12,12 @@ cdef extern from "Python.h":
# PyComplexObject # PyComplexObject
# This subtype of PyObject represents a Python complex number object. # This subtype of PyObject represents a Python complex number object.
ctypedef class __builtin__.complex [object PyComplexObject]:
cdef Py_complex cval
# not making these available to keep them read-only:
#cdef double imag "cval.imag"
#cdef double real "cval.real"
# PyTypeObject PyComplex_Type # PyTypeObject PyComplex_Type
# This instance of PyTypeObject represents the Python complex # This instance of PyTypeObject represents the Python complex
# number type. It is the same object as complex and # number type. It is the same object as complex and
......
cdef extern from "math.h":
enum: M_E
enum: M_LOG2E
enum: M_LOG10E
enum: M_LN2
enum: M_LN10
enum: M_PI
enum: M_PI_2
enum: M_PI_4
enum: M_1_PI
enum: M_2_PI
enum: M_2_SQRTPI
enum: M_SQRT2
enum: M_SQRT1_2
double acos(double x)
double asin(double x)
double atan(double x)
double atan2(double y, double x)
double cos(double x)
double sin(double x)
double tan(double x)
double cosh(double x)
double sinh(double x)
double tanh(double x)
double acosh(double x)
double asinh(double x)
double atanh(double x)
double exp(double x)
double log(double x)
double log10(double x)
double pow(double x, double y)
double sqrt(double x)
__version__ = "0.13+" __version__ = "0.14.alpha0"
# Void cython.* directives (for case insensitive operating systems). # Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import * from Cython.Shadow import *
...@@ -18,7 +18,7 @@ include Demos/Setup.py ...@@ -18,7 +18,7 @@ include Demos/Setup.py
include Demos/Makefile* include Demos/Makefile*
recursive-include Tools * recursive-include Tools *
recursive-include tests *.pyx *.pxd *.pxi *.py *.h *.BROKEN bugs.txt recursive-include tests *.pyx *.pxd *.pxi *.py *.h *.BROKEN bugs.txt
recursive-include tests *_lib.cpp recursive-include tests *_lib.cpp *.srctree
include runtests.py include runtests.py
include Cython/Mac/Makefile include Cython/Mac/Makefile
......
...@@ -749,7 +749,8 @@ class EndToEndTest(unittest.TestCase): ...@@ -749,7 +749,8 @@ class EndToEndTest(unittest.TestCase):
def setUp(self): def setUp(self):
from Cython.TestUtils import unpack_source_tree from Cython.TestUtils import unpack_source_tree
_, self.commands = unpack_source_tree(os.path.join('tests', 'build', self.treefile), self.workdir) _, self.commands = unpack_source_tree(
os.path.join('tests', 'build', self.treefile), self.workdir)
self.old_dir = os.getcwd() self.old_dir = os.getcwd()
os.chdir(self.workdir) os.chdir(self.workdir)
if self.workdir not in sys.path: if self.workdir not in sys.path:
...@@ -764,11 +765,25 @@ class EndToEndTest(unittest.TestCase): ...@@ -764,11 +765,25 @@ class EndToEndTest(unittest.TestCase):
commands = (self.commands commands = (self.commands
.replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py')) .replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py'))
.replace("PYTHON", sys.executable)) .replace("PYTHON", sys.executable))
old_path = os.environ.get('PYTHONPATH')
try: try:
os.environ['PYTHONPATH'] = self.cython_syspath + os.pathsep + (old_path or '') old_path = os.environ.get('PYTHONPATH')
print(os.environ['PYTHONPATH']) os.environ['PYTHONPATH'] = os.path.join(self.cython_syspath, (old_path or ''))
self.assertEqual(0, os.system(commands)) for command in commands.split('\n'):
if sys.version_info[:2] >= (2,4):
import subprocess
p = subprocess.Popen(commands,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
shell=True)
out, err = p.communicate()
res = p.returncode
if res != 0:
print(command)
print(out)
print(err)
else:
res = os.system(command)
self.assertEqual(0, res, "non-zero exit status")
finally: finally:
if old_path: if old_path:
os.environ['PYTHONPATH'] = old_path os.environ['PYTHONPATH'] = old_path
......
cdef int f() except -1:
cdef slice s
cdef object z
cdef int i
z = slice
s = slice(1, 2, 3)
z = slice.indices()
i = s.start
i = s.stop
i = s.step
PYTHON setup.py build_ext --inplace
PYTHON -c "import a; a.use_vector([1,2,3])"
######## setup.py ########
from Cython.Build.Dependencies import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("*.pyx"),
)
######## a.pyx ########
# distutils: language = c++
from libcpp.vector cimport vector
def use_vector(L):
try:
v = new vector[int]()
for a in L:
v.push_back(a)
return v.size()
finally:
del v
PYTHON setup.py build_ext --inplace
PYTHON -c "import a"
######## setup.py ########
from Cython.Build.Dependencies import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("*.pyx", include_path=['subdir'], compiler_directives={'cdivision': True}),
)
######## a.pyx ########
cimport x
include "y.pxi"
# cdivision from setup.py
def mod_int_c(int a, int b):
return a % b
assert mod_int_c(-1, 10) < 0
######## subdir/x.pxd ########
######## subdir/y.pxi ########
from libc.math cimport (M_E, M_LOG2E, M_LOG10E, M_LN2, M_LN10, M_PI, M_PI_2,
M_PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, M_SQRT2, M_SQRT1_2)
from libc.math cimport (acos, asin, atan, atan2, cos, sin, tan, cosh, sinh,
tanh, acosh, asinh, atanh, exp, log, log10, pow, sqrt)
# current restriction: cannot inherit from PyVarObject (see ticket #152)
cdef class MyTuple(tuple):
pass
cdef class MyBytes(bytes):
pass
cdef class MyStr(str): # only in Py2, but can't know that during compilation
pass
_ERRORS = """
4:5: inheritance from PyVarObject types like 'tuple' is not currently supported
7:5: inheritance from PyVarObject types like 'bytes' is not currently supported
10:5: inheritance from PyVarObject types like 'str' is not currently supported
"""
cdef class MyInt(int):
"""
>>> MyInt(2) == 2
True
>>> MyInt(2).attr is None
True
"""
cdef readonly object attr
cdef class MyFloat(float):
"""
>>> MyFloat(1.0)== 1.0
True
>>> MyFloat(1.0).attr is None
True
"""
cdef readonly object attr
ustring = u'abc'
cdef class MyUnicode(unicode):
"""
>>> MyUnicode(ustring) == ustring
True
>>> MyUnicode(ustring).attr is None
True
"""
cdef readonly object attr
cdef class MyList(list):
"""
>>> MyList([1,2,3]) == [1,2,3]
True
>>> MyList([1,2,3]).attr is None
True
"""
cdef readonly object attr
cdef class MyDict(dict):
"""
>>> MyDict({1:2, 3:4}) == {1:2, 3:4}
True
>>> MyDict({1:2, 3:4}).attr is None
True
"""
cdef readonly object attr
from cpython.complex cimport complex
def complex_attributes():
"""
>>> complex_attributes()
(1.0, 2.0)
"""
cdef complex c = 1+2j
return (c.real, c.imag)
def complex_attributes_assign():
"""
>>> complex_attributes_assign()
(10.0, 20.0)
"""
cdef complex c = 1+2j
c.cval.real, c.cval.imag = 10, 20
return (c.real, c.imag)
def complex_cstruct_assign():
"""
>>> complex_cstruct_assign()
(10.0, 20.0)
"""
cdef complex c = 1+2j
cval = &c.cval
cval.real, cval.imag = 10, 20
return (c.real, c.imag)
def complex_coercion():
"""
>>> complex_coercion()
(1.0, 2.0, 1.0, 2.0)
"""
cdef complex py_c = 1+2j
cdef double complex c_c = py_c
cdef object py = c_c
return (c_c.real, c_c.imag, py.real, py.imag)
def complex_arg(complex c):
"""
>>> complex_arg(1+2j)
(1.0, 2.0)
"""
return (c.real, c.imag)
cimport cython
def unbound_method_lookup():
"""
>>> unbound_method_lookup()
"""
ignore = slice.indices
@cython.test_assert_path_exists('//SingleAssignmentNode//AttributeNode[@is_py_attr = False]')
@cython.test_fail_if_path_exists('//SingleAssignmentNode//AttributeNode[@is_py_attr = True]')
def typed_slice():
"""
>>> typed_slice()
(1, 2, 3)
"""
cdef slice s
cdef object z
cdef Py_ssize_t a,b,c
z = slice
s = slice(1, 2, 3)
s.indices
a = s.start
b = s.stop
c = s.step
return (a,b,c)
@cython.test_fail_if_path_exists('//SingleAssignmentNode//AttributeNode[@is_py_attr = False]')
def plain_object_slice():
"""
>>> plain_object_slice()
(1, 2, 3)
"""
cdef object s
cdef object z
cdef Py_ssize_t a,b,c
s = slice(1, 2, 3)
s.indices
a = s.start
b = s.stop
c = s.step
return (a,b,c)
...@@ -18,7 +18,6 @@ def test_non_optimised(): ...@@ -18,7 +18,6 @@ def test_non_optimised():
assert isinstance(A(), foo) assert isinstance(A(), foo)
assert isinstance(0, (int, long)) assert isinstance(0, (int, long))
assert not isinstance(u"xyz", (int, long)) assert not isinstance(u"xyz", (int, long))
assert isinstance(complex(), complex) # FIXME: this should be optimised, too!
return True return True
@cython.test_assert_path_exists('//PythonCapiCallNode', @cython.test_assert_path_exists('//PythonCapiCallNode',
...@@ -46,6 +45,7 @@ def test_optimised(): ...@@ -46,6 +45,7 @@ def test_optimised():
assert isinstance(dict(), dict) assert isinstance(dict(), dict)
assert isinstance(set(), set) assert isinstance(set(), set)
assert isinstance(slice(0), slice) assert isinstance(slice(0), slice)
assert isinstance(complex(), complex)
assert not isinstance(u"foo", int) assert not isinstance(u"foo", int)
assert isinstance(A, type) assert isinstance(A, type)
return True return True
......
cdef int cdef_CONST = 123
CONST = 456
cdef class Foo:
"""
>>> obj = Foo()
>>> obj.id(123)
123
>>> obj.cconst_mul(1)
123
>>> obj.const_mul(1)
456
>>> obj.foo[0](1)
1
"""
id = lambda self, x: x
cconst_mul = lambda self, x: x * cdef_CONST
const_mul = lambda self, x: x * CONST
foo = (lambda x:x,)
class Bar:
"""
>>> obj = Bar()
>>> obj.id(123)
123
>>> obj.cconst_mul(1)
123
>>> obj.const_mul(1)
456
>>> obj.foo[0](1)
1
"""
id = lambda self, x: x
cconst_mul = lambda self, x: x * cdef_CONST
const_mul = lambda self, x: x * CONST
foo = (lambda x:x,)
...@@ -105,6 +105,24 @@ def test_set_discard(): ...@@ -105,6 +105,24 @@ def test_set_discard():
s1.discard(3) s1.discard(3)
return s1 return s1
def test_set_sideeffect_unhashable_failure():
"""
>>> test_set_sideeffect_unhashable_failure()
[2, 4, 5]
"""
L = []
def sideeffect(x):
L.append(x)
return x
def unhashable_value(x):
L.append(x)
return set()
try:
s = set([1,sideeffect(2),3,unhashable_value(4),sideeffect(5)])
except TypeError: pass
else: assert False, "expected exception not raised"
return L
def sorted(it): def sorted(it):
# Py3 can't compare strings to ints # Py3 can't compare strings to ints
chars = [] chars = []
......
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