Commit 7148a1a7 authored by Robert Bradshaw's avatar Robert Bradshaw

Merge closures into main development branch.

parents 8d4fdaad 48d7588a
...@@ -415,7 +415,7 @@ def init_builtins(): ...@@ -415,7 +415,7 @@ def init_builtins():
init_builtin_structs() 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 global float_type, bool_type, type_type, complex_type
type_type = builtin_scope.lookup('type').type type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type tuple_type = builtin_scope.lookup('tuple').type
...@@ -427,5 +427,6 @@ def init_builtins(): ...@@ -427,5 +427,6 @@ def init_builtins():
unicode_type = builtin_scope.lookup('unicode').type unicode_type = builtin_scope.lookup('unicode').type
float_type = builtin_scope.lookup('float').type float_type = builtin_scope.lookup('float').type
bool_type = builtin_scope.lookup('bool').type bool_type = builtin_scope.lookup('bool').type
complex_type = builtin_scope.lookup('complex').type
init_builtins() init_builtins()
...@@ -407,6 +407,7 @@ class GlobalState(object): ...@@ -407,6 +407,7 @@ class GlobalState(object):
code_layout = [ code_layout = [
'h_code', 'h_code',
'filename_table',
'utility_code_proto_before_types', 'utility_code_proto_before_types',
'numeric_typedefs', # Let these detailed individual parts stay!, 'numeric_typedefs', # Let these detailed individual parts stay!,
'complex_type_declarations', # as the proper solution is to make a full DAG... 'complex_type_declarations', # as the proper solution is to make a full DAG...
...@@ -425,7 +426,6 @@ class GlobalState(object): ...@@ -425,7 +426,6 @@ class GlobalState(object):
'cleanup_globals', 'cleanup_globals',
'cleanup_module', 'cleanup_module',
'main_method', 'main_method',
'filename_table',
'utility_code_def', 'utility_code_def',
'end' 'end'
] ]
...@@ -484,11 +484,6 @@ class GlobalState(object): ...@@ -484,11 +484,6 @@ class GlobalState(object):
code.write('\n#line 1 "cython_utility"\n') code.write('\n#line 1 "cython_utility"\n')
code.putln("") code.putln("")
code.putln("/* Runtime support code */") code.putln("/* Runtime support code */")
code.putln("")
code.putln("static void %s(void) {" % Naming.fileinit_cname)
code.putln("%s = %s;" %
(Naming.filetable_cname, Naming.filenames_cname))
code.putln("}")
def finalize_main_c_code(self): def finalize_main_c_code(self):
self.close_global_decls() self.close_global_decls()
......
...@@ -70,7 +70,7 @@ class ControlFlow(object): ...@@ -70,7 +70,7 @@ class ControlFlow(object):
if current is None: if current is None:
return (None, None) return (None, None)
state = current._get_pos_state_local(item, pos) state = current._get_pos_state_local(item, pos)
while state is None and current.incoming is not None: while (state is None or state == (None, None)) and current.incoming is not None:
current = current.incoming current = current.incoming
state = current._get_pos_state_local(item, pos) state = current._get_pos_state_local(item, pos)
if state is None: if state is None:
......
This diff is collapsed.
...@@ -14,6 +14,7 @@ def make_lexicon(): ...@@ -14,6 +14,7 @@ def make_lexicon():
letter = Any("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") letter = Any("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_")
digit = Any("0123456789") digit = Any("0123456789")
bindigit = Any("01")
octdigit = Any("01234567") octdigit = Any("01234567")
hexdigit = Any("0123456789ABCDEFabcdef") hexdigit = Any("0123456789ABCDEFabcdef")
indentation = Bol + Rep(Any(" \t")) indentation = Bol + Rep(Any(" \t"))
...@@ -24,7 +25,9 @@ def make_lexicon(): ...@@ -24,7 +25,9 @@ def make_lexicon():
decimal_fract = (decimal + dot + Opt(decimal)) | (dot + decimal) decimal_fract = (decimal + dot + Opt(decimal)) | (dot + decimal)
name = letter + Rep(letter | digit) name = letter + Rep(letter | digit)
intconst = decimal | (Str("0x") + Rep1(hexdigit)) intconst = decimal | (Str("0") + ((Any("Xx") + Rep1(hexdigit)) |
(Any("Oo") + Rep1(octdigit)) |
(Any("Bb") + Rep1(bindigit)) ))
intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu"))) intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu")))
intliteral = intconst + intsuffix intliteral = intconst + intsuffix
fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent) fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent)
...@@ -72,7 +75,7 @@ def make_lexicon(): ...@@ -72,7 +75,7 @@ def make_lexicon():
punct = Any(":,;+-*/|&<>=.%`~^?") punct = Any(":,;+-*/|&<>=.%`~^?")
diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//", diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//",
"+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=", "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=",
"<<=", ">>=", "**=", "//=") "<<=", ">>=", "**=", "//=", "->")
spaces = Rep1(Any(" \t\f")) spaces = Rep1(Any(" \t\f"))
escaped_newline = Str("\\\n") escaped_newline = Str("\\\n")
lineterm = Eol + Opt(Str("\n")) lineterm = Eol + Opt(Str("\n"))
......
...@@ -136,11 +136,13 @@ class Context(object): ...@@ -136,11 +136,13 @@ class Context(object):
_specific_post_parse, _specific_post_parse,
InterpretCompilerDirectives(self, self.compiler_directives), InterpretCompilerDirectives(self, self.compiler_directives),
_align_function_definitions, _align_function_definitions,
MarkClosureVisitor(self),
ConstantFolding(), ConstantFolding(),
FlattenInListTransform(), FlattenInListTransform(),
WithTransform(self), WithTransform(self),
DecoratorTransform(self), DecoratorTransform(self),
AnalyseDeclarationsTransform(self), AnalyseDeclarationsTransform(self),
CreateClosureClasses(self),
AutoTestDictTransform(self), AutoTestDictTransform(self),
EmbedSignature(self), EmbedSignature(self),
EarlyReplaceBuiltinCalls(self), EarlyReplaceBuiltinCalls(self),
......
...@@ -270,11 +270,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -270,11 +270,14 @@ 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
for node in env.lambda_defs:
node.generate_function_definitions(env, code)
# 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)
self.generate_typeobj_definitions(env, code) self.generate_typeobj_definitions(env, code)
self.generate_method_table(env, code) self.generate_method_table(env, code)
self.generate_filename_init_prototype(code)
if env.has_import_star: if env.has_import_star:
self.generate_import_star(env, code) self.generate_import_star(env, code)
self.generate_pymoduledef_struct(env, code) self.generate_pymoduledef_struct(env, code)
...@@ -545,6 +548,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -545,6 +548,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
#define PyBytes_Repr PyString_Repr #define PyBytes_Repr PyString_Repr
#define PyBytes_Concat PyString_Concat #define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel #define PyBytes_ConcatAndDel PyString_ConcatAndDel
#define PySet_Check(obj) PyObject_TypeCheck(obj, &PySet_Type)
#define PyFrozenSet_Check(obj) PyObject_TypeCheck(obj, &PyFrozenSet_Type)
#endif
#ifndef PySet_CheckExact
# define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
#endif #endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
...@@ -580,7 +589,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -580,7 +589,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put(""" code.put("""
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
#define PyMethod_New(func, self, klass) PyInstanceMethod_New(func) #define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func))
#endif #endif
#if PY_VERSION_HEX < 0x02050000 #if PY_VERSION_HEX < 0x02050000
...@@ -631,7 +640,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -631,7 +640,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln('static int %s = 0;' % Naming.clineno_cname) code.putln('static int %s = 0;' % Naming.clineno_cname)
code.putln('static const char * %s= %s;' % (Naming.cfilenm_cname, Naming.file_c_macro)) code.putln('static const char * %s= %s;' % (Naming.cfilenm_cname, Naming.file_c_macro))
code.putln('static const char *%s;' % Naming.filename_cname) code.putln('static const char *%s;' % Naming.filename_cname)
code.putln('static const char **%s;' % Naming.filetable_cname)
# XXX this is a mess # XXX this is a mess
for utility_code in PyrexTypes.c_int_from_py_function.specialize_list: for utility_code in PyrexTypes.c_int_from_py_function.specialize_list:
...@@ -658,13 +666,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -658,13 +666,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_filename_table(self, code): def generate_filename_table(self, code):
code.putln("") code.putln("")
code.putln("static const char *%s[] = {" % Naming.filenames_cname) code.putln("static const char *%s[] = {" % Naming.filetable_cname)
if code.globalstate.filename_list: if code.globalstate.filename_list:
for source_desc in code.globalstate.filename_list: for source_desc in code.globalstate.filename_list:
filename = os.path.basename(source_desc.get_filenametable_entry()) filename = os.path.basename(source_desc.get_filenametable_entry())
escaped_filename = filename.replace("\\", "\\\\").replace('"', r'\"') escaped_filename = filename.replace("\\", "\\\\").replace('"', r'\"')
code.putln('"%s",' % code.putln('"%s",' % escaped_filename)
escaped_filename)
else: else:
# Some C compilers don't like an empty array # Some C compilers don't like an empty array
code.putln("0") code.putln("0")
...@@ -1003,7 +1010,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1003,7 +1010,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.vtabslot_cname, type.vtabslot_cname,
struct_type_cast, type.vtabptr_cname)) struct_type_cast, type.vtabptr_cname))
for entry in py_attrs: for entry in py_attrs:
if entry.name == "__weakref__": if scope.is_internal or entry.name == "__weakref__":
# internal classes do not need None inits
code.putln("p->%s = 0;" % entry.cname) code.putln("p->%s = 0;" % entry.cname)
else: else:
code.put_init_var_to_py_none(entry, "p->%s", nanny=False) code.put_init_var_to_py_none(entry, "p->%s", nanny=False)
...@@ -1584,10 +1592,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1584,10 +1592,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln( code.putln(
"};") "};")
def generate_filename_init_prototype(self, code):
code.putln("");
code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname)
def generate_import_star(self, env, code): def generate_import_star(self, env, code):
env.use_utility_code(streq_utility_code) env.use_utility_code(streq_utility_code)
code.putln() code.putln()
...@@ -1678,11 +1682,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1678,11 +1682,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("__pyx_refnanny = __Pyx_RefNanny->SetupContext(\"%s\", __LINE__, __FILE__);"% header3) code.putln("__pyx_refnanny = __Pyx_RefNanny->SetupContext(\"%s\", __LINE__, __FILE__);"% header3)
code.putln("#endif") 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("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)));
code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos)));
code.putln("#ifdef %s_USED" % Naming.binding_cfunc)
code.putln("if (%s_init() < 0) %s" % (Naming.binding_cfunc, code.error_goto(self.pos)))
code.putln("#endif")
code.putln("/*--- Library function declarations ---*/") code.putln("/*--- Library function declarations ---*/")
env.generate_library_function_declarations(code) env.generate_library_function_declarations(code)
...@@ -1816,9 +1822,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1816,9 +1822,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
module_is_main = "%s%s" % (Naming.module_is_main, self.full_module_name.replace('.', '__')) 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)) 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)
def generate_pymoduledef_struct(self, env, code): def generate_pymoduledef_struct(self, env, code):
if env.doc: if env.doc:
doc = "__Pyx_DOCSTR(%s)" % code.get_string_const(env.doc) doc = "__Pyx_DOCSTR(%s)" % code.get_string_const(env.doc)
......
...@@ -44,6 +44,9 @@ vtabptr_prefix = pyrex_prefix + "vtabptr_" ...@@ -44,6 +44,9 @@ vtabptr_prefix = pyrex_prefix + "vtabptr_"
vtabstruct_prefix = pyrex_prefix + "vtabstruct_" vtabstruct_prefix = pyrex_prefix + "vtabstruct_"
opt_arg_prefix = pyrex_prefix + "opt_args_" opt_arg_prefix = pyrex_prefix + "opt_args_"
convert_func_prefix = pyrex_prefix + "convert_" convert_func_prefix = pyrex_prefix + "convert_"
closure_scope_prefix = pyrex_prefix + "scope_"
closure_class_prefix = pyrex_prefix + "scope_struct_"
lambda_func_prefix = pyrex_prefix + "lambda_"
module_is_main = pyrex_prefix + "module_is_main_" module_is_main = pyrex_prefix + "module_is_main_"
args_cname = pyrex_prefix + "args" args_cname = pyrex_prefix + "args"
...@@ -56,8 +59,6 @@ dummy_cname = pyrex_prefix + "dummy" ...@@ -56,8 +59,6 @@ dummy_cname = pyrex_prefix + "dummy"
filename_cname = pyrex_prefix + "filename" filename_cname = pyrex_prefix + "filename"
modulename_cname = pyrex_prefix + "modulename" modulename_cname = pyrex_prefix + "modulename"
filetable_cname = pyrex_prefix + "f" filetable_cname = pyrex_prefix + "f"
filenames_cname = pyrex_prefix + "filenames"
fileinit_cname = pyrex_prefix + "init_filenames"
intern_tab_cname = pyrex_prefix + "intern_tab" intern_tab_cname = pyrex_prefix + "intern_tab"
kwds_cname = pyrex_prefix + "kwds" kwds_cname = pyrex_prefix + "kwds"
lineno_cname = pyrex_prefix + "lineno" lineno_cname = pyrex_prefix + "lineno"
...@@ -83,10 +84,14 @@ pymoduledef_cname = pyrex_prefix + "moduledef" ...@@ -83,10 +84,14 @@ pymoduledef_cname = pyrex_prefix + "moduledef"
optional_args_cname = pyrex_prefix + "optional_args" optional_args_cname = pyrex_prefix + "optional_args"
import_star = pyrex_prefix + "import_star" import_star = pyrex_prefix + "import_star"
import_star_set = pyrex_prefix + "import_star_set" import_star_set = pyrex_prefix + "import_star_set"
outer_scope_cname= pyrex_prefix + "outer_scope"
cur_scope_cname = pyrex_prefix + "cur_scope" cur_scope_cname = pyrex_prefix + "cur_scope"
enc_scope_cname = pyrex_prefix + "enc_scope" enc_scope_cname = pyrex_prefix + "enc_scope"
frame_cname = pyrex_prefix + "frame" frame_cname = pyrex_prefix + "frame"
frame_code_cname = pyrex_prefix + "frame_code" frame_code_cname = pyrex_prefix + "frame_code"
binding_cfunc = pyrex_prefix + "binding_PyCFunctionType"
genexpr_id_ref = 'genexpr'
line_c_macro = "__LINE__" line_c_macro = "__LINE__"
......
This diff is collapsed.
This diff is collapsed.
...@@ -74,6 +74,9 @@ directive_defaults = { ...@@ -74,6 +74,9 @@ directive_defaults = {
# test support # test support
'test_assert_path_exists' : [], 'test_assert_path_exists' : [],
'test_fail_if_path_exists' : [], 'test_fail_if_path_exists' : [],
# experimental, subject to change
'binding': False,
} }
# Override types possibilities above, if needed # Override types possibilities above, if needed
......
...@@ -177,6 +177,7 @@ class PostParse(CythonTransform): ...@@ -177,6 +177,7 @@ class PostParse(CythonTransform):
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
self.scope_type = 'module' self.scope_type = 'module'
self.scope_node = node self.scope_node = node
self.lambda_counter = 1
self.visitchildren(node) self.visitchildren(node)
return node return node
...@@ -197,6 +198,25 @@ class PostParse(CythonTransform): ...@@ -197,6 +198,25 @@ class PostParse(CythonTransform):
def visit_CStructOrUnionDefNode(self, node): def visit_CStructOrUnionDefNode(self, node):
return self.visit_scope(node, 'struct') return self.visit_scope(node, 'struct')
def visit_LambdaNode(self, node):
# unpack a lambda expression into the corresponding DefNode
if self.scope_type != 'function':
error(node.pos,
"lambda functions are currently only supported in functions")
lambda_id = self.lambda_counter
self.lambda_counter += 1
node.lambda_name = EncodedString(u'lambda%d' % lambda_id)
body = Nodes.ReturnStatNode(
node.result_expr.pos, value = node.result_expr)
node.def_node = Nodes.DefNode(
node.pos, name=node.name, lambda_name=node.lambda_name,
args=node.args, star_arg=node.star_arg,
starstar_arg=node.starstar_arg,
body=body)
self.visitchildren(node)
return node
# 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, DictNode):
...@@ -984,6 +1004,11 @@ property NAME: ...@@ -984,6 +1004,11 @@ property NAME:
self.seen_vars_stack.pop() self.seen_vars_stack.pop()
return node return node
def visit_LambdaNode(self, node):
node.analyse_declarations(self.env_stack[-1])
self.visitchildren(node)
return node
def visit_ClassDefNode(self, node): def visit_ClassDefNode(self, node):
self.env_stack.append(node.scope) self.env_stack.append(node.scope)
self.visitchildren(node) self.visitchildren(node)
...@@ -1014,6 +1039,23 @@ property NAME: ...@@ -1014,6 +1039,23 @@ property NAME:
node.analyse_declarations(self.env_stack[-1]) node.analyse_declarations(self.env_stack[-1])
return node return node
def visit_ScopedExprNode(self, node):
node.analyse_declarations(self.env_stack[-1])
if self.seen_vars_stack:
self.seen_vars_stack.append(set(self.seen_vars_stack[-1]))
else:
self.seen_vars_stack.append(set())
self.env_stack.append(node.expr_scope)
self.visitchildren(node)
self.env_stack.pop()
self.seen_vars_stack.pop()
return node
def visit_TempResultFromStatNode(self, node):
self.visitchildren(node)
node.analyse_declarations(self.env_stack[-1])
return node
# Some nodes are no longer needed after declaration # Some nodes are no longer needed after declaration
# analysis and can be dropped. The analysis was performed # analysis and can be dropped. The analysis was performed
# on these nodes in a seperate recursive process from the # on these nodes in a seperate recursive process from the
...@@ -1111,6 +1153,13 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -1111,6 +1153,13 @@ class AnalyseExpressionsTransform(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_ScopedExprNode(self, node):
if node.expr_scope is not None:
node.expr_scope.infer_types()
node.analyse_scoped_expressions(node.expr_scope)
self.visitchildren(node)
return node
class AlignFunctionDefinitions(CythonTransform): class AlignFunctionDefinitions(CythonTransform):
""" """
This class takes the signatures from a .pxd file and applies them to This class takes the signatures from a .pxd file and applies them to
...@@ -1176,13 +1225,24 @@ class MarkClosureVisitor(CythonTransform): ...@@ -1176,13 +1225,24 @@ class MarkClosureVisitor(CythonTransform):
self.needs_closure = True self.needs_closure = True
return node return node
def visit_ClassDefNode(self, node): def visit_CFuncDefNode(self, node):
self.visit_FuncDefNode(node)
if node.needs_closure:
error(node.pos, "closures inside cdef functions not yet supported")
return node
def visit_LambdaNode(self, node):
self.needs_closure = False
self.visitchildren(node) self.visitchildren(node)
node.needs_closure = self.needs_closure
self.needs_closure = True self.needs_closure = True
return node return node
def visit_YieldNode(self, node): def visit_ClassDefNode(self, node):
self.visitchildren(node)
self.needs_closure = True self.needs_closure = True
return node
class CreateClosureClasses(CythonTransform): class CreateClosureClasses(CythonTransform):
# Output closure classes in module scope for all functions # Output closure classes in module scope for all functions
...@@ -1194,21 +1254,39 @@ class CreateClosureClasses(CythonTransform): ...@@ -1194,21 +1254,39 @@ class CreateClosureClasses(CythonTransform):
return node return node
def create_class_from_scope(self, node, target_module_scope): def create_class_from_scope(self, node, target_module_scope):
as_name = temp_name_handle("closure") as_name = "%s%s" % (Naming.closure_class_prefix, node.entry.cname)
func_scope = node.local_scope func_scope = node.local_scope
entry = target_module_scope.declare_c_class(name = as_name, entry = target_module_scope.declare_c_class(name = as_name,
pos = node.pos, defining = True, implementing = True) pos = node.pos, defining = True, implementing = True)
func_scope.scope_class = entry
class_scope = entry.type.scope class_scope = entry.type.scope
for entry in func_scope.entries.values(): class_scope.is_internal = True
if node.entry.scope.is_closure_scope:
class_scope.declare_var(pos=node.pos, class_scope.declare_var(pos=node.pos,
name=Naming.outer_scope_cname, # this could conflict?
cname=Naming.outer_scope_cname,
type=node.entry.scope.scope_class.type,
is_cdef=True)
entries = func_scope.entries.items()
entries.sort()
for name, entry in entries:
# This is wasteful--we should do this later when we know
# which vars are actually being used inside...
#
# Also, this happens before type inference and type
# analysis, so the entries created here may end up having
# incorrect or at least unspecified types.
class_scope.declare_var(pos=entry.pos,
name=entry.name, name=entry.name,
cname=entry.cname, cname=entry.cname,
type=entry.type, type=entry.type,
is_cdef=True) is_cdef=True)
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
if node.needs_closure:
self.create_class_from_scope(node, self.module_scope) self.create_class_from_scope(node, self.module_scope)
self.visitchildren(node)
return node return node
......
...@@ -6,17 +6,21 @@ from Cython.Compiler.Scanning cimport PyrexScanner ...@@ -6,17 +6,21 @@ from Cython.Compiler.Scanning cimport PyrexScanner
cpdef p_ident(PyrexScanner s, message =*) cpdef p_ident(PyrexScanner s, message =*)
cpdef p_ident_list(PyrexScanner s) cpdef p_ident_list(PyrexScanner s)
cpdef p_binop_operator(PyrexScanner s)
cpdef p_binop_expr(PyrexScanner s, ops, p_sub_expr) cpdef p_binop_expr(PyrexScanner s, ops, p_sub_expr)
cpdef p_simple_expr(PyrexScanner s) cpdef p_lambdef(PyrexScanner s, bint allow_conditional=*)
cpdef p_lambdef_nocond(PyrexScanner s)
cpdef p_test(PyrexScanner s) cpdef p_test(PyrexScanner s)
cpdef p_test_nocond(PyrexScanner s)
cpdef p_or_test(PyrexScanner s) cpdef p_or_test(PyrexScanner s)
cpdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr) cpdef p_rassoc_binop_expr(PyrexScanner s, ops, p_subexpr)
cpdef p_and_test(PyrexScanner s) cpdef p_and_test(PyrexScanner s)
cpdef p_not_test(PyrexScanner s) cpdef p_not_test(PyrexScanner s)
cpdef p_comparison(PyrexScanner s) cpdef p_comparison(PyrexScanner s)
cpdef p_test_or_starred_expr(PyrexScanner s)
cpdef p_starred_expr(PyrexScanner s)
cpdef p_cascaded_cmp(PyrexScanner s) cpdef p_cascaded_cmp(PyrexScanner s)
cpdef p_cmp_op(PyrexScanner s) cpdef p_cmp_op(PyrexScanner s)
cpdef p_starred_expr(PyrexScanner s)
cpdef p_bit_expr(PyrexScanner s) cpdef p_bit_expr(PyrexScanner s)
cpdef p_xor_expr(PyrexScanner s) cpdef p_xor_expr(PyrexScanner s)
cpdef p_and_expr(PyrexScanner s) cpdef p_and_expr(PyrexScanner s)
...@@ -27,6 +31,7 @@ cpdef p_factor(PyrexScanner s) ...@@ -27,6 +31,7 @@ cpdef p_factor(PyrexScanner s)
cpdef p_typecast(PyrexScanner s) cpdef p_typecast(PyrexScanner s)
cpdef p_sizeof(PyrexScanner s) cpdef p_sizeof(PyrexScanner s)
cpdef p_yield_expression(PyrexScanner s) cpdef p_yield_expression(PyrexScanner s)
cpdef p_yield_statement(PyrexScanner s)
cpdef p_power(PyrexScanner s) cpdef p_power(PyrexScanner s)
cpdef p_new_expr(PyrexScanner s) cpdef p_new_expr(PyrexScanner s)
cpdef p_trailer(PyrexScanner s, node1) cpdef p_trailer(PyrexScanner s, node1)
...@@ -44,14 +49,17 @@ cpdef p_cat_string_literal(PyrexScanner s) ...@@ -44,14 +49,17 @@ cpdef p_cat_string_literal(PyrexScanner s)
cpdef p_opt_string_literal(PyrexScanner s) cpdef p_opt_string_literal(PyrexScanner s)
cpdef p_string_literal(PyrexScanner s, kind_override=*) cpdef p_string_literal(PyrexScanner s, kind_override=*)
cpdef p_list_maker(PyrexScanner s) cpdef p_list_maker(PyrexScanner s)
cpdef p_list_iter(PyrexScanner s, body) cpdef p_comp_iter(PyrexScanner s, body)
cpdef p_list_for(PyrexScanner s, body) cpdef p_comp_for(PyrexScanner s, body)
cpdef p_list_if(PyrexScanner s, body) cpdef p_comp_if(PyrexScanner s, body)
cpdef p_dict_or_set_maker(PyrexScanner s) cpdef p_dict_or_set_maker(PyrexScanner s)
cpdef p_backquote_expr(PyrexScanner s) cpdef p_backquote_expr(PyrexScanner s)
cpdef p_simple_expr_list(PyrexScanner s) cpdef p_simple_expr_list(PyrexScanner s, expr=*)
cpdef p_expr(PyrexScanner s) cpdef p_test_or_starred_expr_list(s, expr=*)
cpdef p_testlist(PyrexScanner s) cpdef p_testlist(PyrexScanner s)
cpdef p_testlist_star_expr(PyrexScanner s)
cpdef p_testlist_comp(PyrexScanner s)
cpdef p_genexp(PyrexScanner s, expr)
#------------------------------------------------------- #-------------------------------------------------------
# #
...@@ -80,12 +88,12 @@ cpdef p_if_clause(PyrexScanner s) ...@@ -80,12 +88,12 @@ cpdef p_if_clause(PyrexScanner s)
cpdef p_else_clause(PyrexScanner s) cpdef p_else_clause(PyrexScanner s)
cpdef p_while_statement(PyrexScanner s) cpdef p_while_statement(PyrexScanner s)
cpdef p_for_statement(PyrexScanner s) cpdef p_for_statement(PyrexScanner s)
cpdef p_for_bounds(PyrexScanner s) cpdef p_for_bounds(PyrexScanner s, bint allow_testlist = *)
cpdef p_for_from_relation(PyrexScanner s) cpdef p_for_from_relation(PyrexScanner s)
cpdef p_for_from_step(PyrexScanner s) cpdef p_for_from_step(PyrexScanner s)
cpdef p_target(PyrexScanner s, terminator) cpdef p_target(PyrexScanner s, terminator)
cpdef p_for_target(PyrexScanner s) cpdef p_for_target(PyrexScanner s)
cpdef p_for_iterator(PyrexScanner s) cpdef p_for_iterator(PyrexScanner s, bint allow_testlist = *)
cpdef p_try_statement(PyrexScanner s) cpdef p_try_statement(PyrexScanner s)
cpdef p_except_clause(PyrexScanner s) cpdef p_except_clause(PyrexScanner s)
cpdef p_include_statement(PyrexScanner s, ctx) cpdef p_include_statement(PyrexScanner s, ctx)
...@@ -122,23 +130,24 @@ cpdef p_nogil(PyrexScanner s) ...@@ -122,23 +130,24 @@ cpdef p_nogil(PyrexScanner s)
cpdef p_with_gil(PyrexScanner s) cpdef p_with_gil(PyrexScanner s)
cpdef p_exception_value_clause(PyrexScanner s) cpdef p_exception_value_clause(PyrexScanner s)
cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *, cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *,
bint nonempty_declarators = *, bint kw_only = *) bint nonempty_declarators = *, bint kw_only = *, bint annotated = *)
cpdef p_optional_ellipsis(PyrexScanner s) cpdef p_optional_ellipsis(PyrexScanner s)
cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *) cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *, bint annotated = *)
cpdef p_api(PyrexScanner s) cpdef p_api(PyrexScanner s)
cpdef p_cdef_statement(PyrexScanner s, ctx) cpdef p_cdef_statement(PyrexScanner s, ctx)
cpdef p_cdef_block(PyrexScanner s, ctx) cpdef p_cdef_block(PyrexScanner s, ctx)
cpdef p_cdef_extern_block(PyrexScanner s, pos, ctx) cpdef p_cdef_extern_block(PyrexScanner s, pos, ctx)
cpdef p_c_enum_definition(PyrexScanner s, pos, ctx) cpdef p_c_enum_definition(PyrexScanner s, pos, ctx)
cpdef p_c_enum_line(PyrexScanner s, ctx, items) cpdef p_c_enum_line(PyrexScanner s, ctx, list items)
cpdef p_c_enum_item(PyrexScanner s, ctx, items) cpdef p_c_enum_item(PyrexScanner s, ctx, list items)
cpdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx) cpdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
cpdef p_visibility(PyrexScanner s, prev_visibility) cpdef p_visibility(PyrexScanner s, prev_visibility)
cpdef p_c_modifiers(PyrexScanner s) cpdef p_c_modifiers(PyrexScanner s)
cpdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx) cpdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
cpdef p_ctypedef_statement(PyrexScanner s, ctx) cpdef p_ctypedef_statement(PyrexScanner s, ctx)
cpdef p_decorators(PyrexScanner s) cpdef p_decorators(PyrexScanner s)
cpdef p_def_statement(PyrexScanner s, decorators = *) cpdef p_def_statement(PyrexScanner s, list decorators = *)
cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cpdef p_py_arg_decl(PyrexScanner s) cpdef p_py_arg_decl(PyrexScanner s)
cpdef p_class_statement(PyrexScanner s, decorators) cpdef p_class_statement(PyrexScanner s, decorators)
cpdef p_c_class_definition(PyrexScanner s, pos, ctx) cpdef p_c_class_definition(PyrexScanner s, pos, ctx)
......
This diff is collapsed.
...@@ -417,19 +417,26 @@ class BuiltinObjectType(PyObjectType): ...@@ -417,19 +417,26 @@ class BuiltinObjectType(PyObjectType):
def subtype_of(self, type): def subtype_of(self, type):
return type.is_pyobject and self.assignable_from(type) return type.is_pyobject and self.assignable_from(type)
def type_test_code(self, arg, notnone=False): def type_check_function(self, exact=True):
type_name = self.name type_name = self.name
if type_name == 'bool':
return 'PyBool_Check'
if type_name == 'str': if type_name == 'str':
type_check = 'PyString_CheckExact' type_check = 'PyString_Check'
elif type_name == 'set':
type_check = 'PyAnySet_CheckExact'
elif type_name == 'frozenset': elif type_name == 'frozenset':
type_check = 'PyFrozenSet_CheckExact' type_check = 'PyFrozenSet_Check'
elif type_name == 'bool':
type_check = 'PyBool_Check'
else: else:
type_check = 'Py%s_CheckExact' % type_name.capitalize() type_check = 'Py%s_Check' % type_name.capitalize()
if exact:
type_check += 'Exact'
return type_check
def isinstance_code(self, arg):
return '%s(%s)' % (self.type_check_function(exact=False), arg)
def type_test_code(self, arg, notnone=False):
type_check = self.type_check_function(exact=True)
check = 'likely(%s(%s))' % (type_check, arg) check = 'likely(%s(%s))' % (type_check, arg)
if not notnone: if not notnone:
check = check + ('||((%s) == Py_None)' % arg) check = check + ('||((%s) == Py_None)' % arg)
......
...@@ -20,6 +20,7 @@ try: ...@@ -20,6 +20,7 @@ try:
set set
except NameError: except NameError:
from sets import Set as set from sets import Set as set
import copy
possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match possible_identifier = re.compile(ur"(?![0-9])\w+$", re.U).match
nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match nice_identifier = re.compile('^[a-zA-Z0-0_]+$').match
...@@ -146,6 +147,7 @@ class Entry(object): ...@@ -146,6 +147,7 @@ class Entry(object):
is_arg = 0 is_arg = 0
is_local = 0 is_local = 0
in_closure = 0 in_closure = 0
from_closure = 0
is_declared_generic = 0 is_declared_generic = 0
is_readonly = 0 is_readonly = 0
func_cname = None func_cname = None
...@@ -207,6 +209,7 @@ class Scope(object): ...@@ -207,6 +209,7 @@ class Scope(object):
# return_type PyrexType or None Return type of function owning scope # return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope # is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope # is_c_class_scope boolean Is an extension type scope
# is_closure_scope boolean
# is_cpp_class_scope boolean Is a C++ class scope # is_cpp_class_scope boolean Is a C++ class scope
# is_property_scope boolean Is a extension type property scope # is_property_scope boolean Is a extension type property scope
# scope_prefix string Disambiguator for C names # scope_prefix string Disambiguator for C names
...@@ -218,12 +221,15 @@ class Scope(object): ...@@ -218,12 +221,15 @@ class Scope(object):
# nogil boolean In a nogil section # nogil boolean In a nogil section
# directives dict Helper variable for the recursive # directives dict Helper variable for the recursive
# analysis, contains directive values. # analysis, contains directive values.
# is_internal boolean Is only used internally (simpler setup)
is_py_class_scope = 0 is_py_class_scope = 0
is_c_class_scope = 0 is_c_class_scope = 0
is_closure_scope = 0
is_cpp_class_scope = 0 is_cpp_class_scope = 0
is_property_scope = 0 is_property_scope = 0
is_module_scope = 0 is_module_scope = 0
is_internal = 0
scope_prefix = "" scope_prefix = ""
in_cinclude = 0 in_cinclude = 0
nogil = 0 nogil = 0
...@@ -260,8 +266,10 @@ class Scope(object): ...@@ -260,8 +266,10 @@ class Scope(object):
self.obj_to_entry = {} self.obj_to_entry = {}
self.pystring_entries = [] self.pystring_entries = []
self.buffer_entries = [] self.buffer_entries = []
self.lambda_defs = []
self.control_flow = ControlFlow.LinearControlFlow() self.control_flow = ControlFlow.LinearControlFlow()
self.return_type = None self.return_type = None
self.id_counters = {}
def start_branching(self, pos): def start_branching(self, pos):
self.control_flow = self.control_flow.start_branch(pos) self.control_flow = self.control_flow.start_branch(pos)
...@@ -291,6 +299,18 @@ class Scope(object): ...@@ -291,6 +299,18 @@ class Scope(object):
return self.mangle(prefix) return self.mangle(prefix)
#return self.parent_scope.mangle(prefix, self.name) #return self.parent_scope.mangle(prefix, self.name)
def next_id(self, name=None):
# Return a cname fragment that is unique for this scope.
try:
count = self.id_counters[name] + 1
except KeyError:
count = 0
self.id_counters[name] = count
if name:
return '%s%d' % (name, count)
else:
return '%d' % count
def global_scope(self): def global_scope(self):
# Return the module-level scope containing this scope. # Return the module-level scope containing this scope.
return self.outer_scope.global_scope() return self.outer_scope.global_scope()
...@@ -482,7 +502,7 @@ class Scope(object): ...@@ -482,7 +502,7 @@ class Scope(object):
error(pos, "C++ class must have a default constructor to be stack allocated") error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
self.control_flow.set_state((), (name, 'initalized'), False) self.control_flow.set_state((), (name, 'initialized'), False)
return entry return entry
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
...@@ -499,6 +519,19 @@ class Scope(object): ...@@ -499,6 +519,19 @@ class Scope(object):
self.pyfunc_entries.append(entry) self.pyfunc_entries.append(entry)
return entry return entry
def declare_lambda_function(self, func_cname, pos):
# Add an entry for an anonymous Python function.
entry = self.declare_var(None, py_object_type, pos,
cname=func_cname, visibility='private')
entry.name = EncodedString(func_cname)
entry.func_cname = func_cname
entry.signature = pyfunction_signature
self.pyfunc_entries.append(entry)
return entry
def add_lambda_def(self, def_node):
self.lambda_defs.append(def_node)
def register_pyfunction(self, entry): def register_pyfunction(self, entry):
self.pyfunc_entries.append(entry) self.pyfunc_entries.append(entry)
...@@ -577,14 +610,7 @@ class Scope(object): ...@@ -577,14 +610,7 @@ class Scope(object):
# Look up name in this scope or an enclosing one. # Look up name in this scope or an enclosing one.
# Return None if not found. # Return None if not found.
return (self.lookup_here(name) return (self.lookup_here(name)
or (self.outer_scope and self.outer_scope.lookup_from_inner(name)) or (self.outer_scope and self.outer_scope.lookup(name))
or None)
def lookup_from_inner(self, name):
# Look up name in this scope or an enclosing one.
# This is only called from enclosing scopes.
return (self.lookup_here(name)
or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
or None) or None)
def lookup_here(self, name): def lookup_here(self, name):
...@@ -1202,31 +1228,94 @@ class LocalScope(Scope): ...@@ -1202,31 +1228,94 @@ class LocalScope(Scope):
entry = self.global_scope().lookup_target(name) entry = self.global_scope().lookup_target(name)
self.entries[name] = entry self.entries[name] = entry
def lookup_from_inner(self, name): def lookup(self, name):
entry = self.lookup_here(name) # Look up name in this scope or an enclosing one.
if entry: # Return None if not found.
entry.in_closure = 1 entry = Scope.lookup(self, name)
if entry is not None:
if entry.scope is not self and entry.scope.is_closure_scope:
# The actual c fragment for the different scopes differs
# on the outside and inside, so we make a new entry
entry.in_closure = True
# Would it be better to declare_var here?
inner_entry = Entry(entry.name, entry.cname, entry.type, entry.pos)
inner_entry.scope = self
inner_entry.is_variable = True
inner_entry.outer_entry = entry
inner_entry.from_closure = True
self.entries[name] = inner_entry
return inner_entry
return entry return entry
else:
return (self.outer_scope and self.outer_scope.lookup_from_inner(name)) or None
def mangle_closure_cnames(self, scope_var): def mangle_closure_cnames(self, outer_scope_cname):
for entry in self.entries.values(): for entry in self.entries.values():
if entry.in_closure: if entry.from_closure:
if not hasattr(entry, 'orig_cname'): cname = entry.outer_entry.cname
entry.orig_cname = entry.cname if cname.startswith(Naming.cur_scope_cname):
entry.cname = scope_var + "->" + entry.cname cname = cname[len(Naming.cur_scope_cname)+2:]
entry.cname = "%s->%s" % (outer_scope_cname, cname)
elif entry.in_closure:
entry.original_cname = entry.cname
entry.cname = "%s->%s" % (Naming.cur_scope_cname, entry.cname)
class GeneratorExpressionScope(LocalScope):
"""Scope for generator expressions and comprehensions. As opposed
to generators, these can be easily inlined in some cases, so all
we really need is a scope that holds the loop variable(s).
"""
def __init__(self, outer_scope):
name = outer_scope.global_scope().next_id(Naming.genexpr_id_ref)
LocalScope.__init__(self, name, outer_scope)
self.directives = outer_scope.directives
self.genexp_prefix = "%s%d%s" % (Naming.pyrex_prefix, len(name), name)
def mangle(self, prefix, name):
return '%s%s' % (self.genexp_prefix, self.outer_scope.mangle(self, prefix, name))
def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = True):
if type is unspecified_type:
# if the outer scope defines a type for this variable, inherit it
outer_entry = self.outer_scope.lookup(name)
if outer_entry and outer_entry.is_variable:
type = outer_entry.type # may still be 'unspecified_type' !
# the outer scope needs to generate code for the variable, but
# this scope must hold its name exclusively
cname = '%s%s' % (self.genexp_prefix, self.outer_scope.mangle(Naming.var_prefix, name))
entry = self.outer_scope.declare_var(None, type, pos, cname, visibility, is_cdef = True)
self.entries[name] = entry
return entry
class ClosureScope(LocalScope):
class GeneratorLocalScope(LocalScope): is_closure_scope = True
def mangle_closure_cnames(self, scope_var): def __init__(self, name, scope_name, outer_scope):
LocalScope.__init__(self, name, outer_scope)
self.closure_cname = "%s%s" % (Naming.closure_scope_prefix, scope_name)
# def mangle_closure_cnames(self, scope_var):
# for entry in self.entries.values() + self.temp_entries: # for entry in self.entries.values() + self.temp_entries:
# entry.in_closure = 1 # entry.in_closure = 1
LocalScope.mangle_closure_cnames(self, scope_var) # LocalScope.mangle_closure_cnames(self, scope_var)
# def mangle(self, prefix, name): # def mangle(self, prefix, name):
# return "%s->%s" % (Naming.scope_obj_cname, name) # return "%s->%s" % (self.cur_scope_cname, name)
# return "%s->%s" % (self.closure_cname, name)
def declare_pyfunction(self, name, pos):
# Add an entry for a Python function.
entry = self.lookup_here(name)
if entry and not entry.type.is_cfunction:
# This is legal Python, but for now may produce invalid C.
error(pos, "'%s' already declared" % name)
entry = self.declare_var(name, py_object_type, pos)
entry.signature = pyfunction_signature
self.pyfunc_entries.append(entry)
return entry
class StructOrUnionScope(Scope): class StructOrUnionScope(Scope):
# Namespace of a C struct or union. # Namespace of a C struct or union.
......
...@@ -196,7 +196,7 @@ class MarkOverflowingArithmetic(CythonTransform): ...@@ -196,7 +196,7 @@ class MarkOverflowingArithmetic(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
return node return node
class PyObjectTypeInferer: class PyObjectTypeInferer(object):
""" """
If it's not declared, it's a PyObject. If it's not declared, it's a PyObject.
""" """
...@@ -208,14 +208,14 @@ class PyObjectTypeInferer: ...@@ -208,14 +208,14 @@ class PyObjectTypeInferer:
if entry.type is unspecified_type: if entry.type is unspecified_type:
entry.type = py_object_type entry.type = py_object_type
class SimpleAssignmentTypeInferer: class SimpleAssignmentTypeInferer(object):
""" """
Very basic type inference. Very basic type inference.
""" """
# TODO: Implement a real type inference algorithm. # TODO: Implement a real type inference algorithm.
# (Something more powerful than just extending this one...) # (Something more powerful than just extending this one...)
def infer_types(self, scope): def infer_types(self, scope):
enabled = scope.directives['infer_types'] enabled = not scope.is_closure_scope and scope.directives['infer_types']
verbose = scope.directives['infer_types.verbose'] verbose = scope.directives['infer_types.verbose']
if enabled == True: if enabled == True:
spanning_type = aggressive_spanning_type spanning_type = aggressive_spanning_type
...@@ -225,6 +225,8 @@ class SimpleAssignmentTypeInferer: ...@@ -225,6 +225,8 @@ class SimpleAssignmentTypeInferer:
for entry in scope.entries.values(): for entry in scope.entries.values():
if entry.type is unspecified_type: if entry.type is unspecified_type:
entry.type = py_object_type entry.type = py_object_type
if scope.is_closure_scope:
fix_closure_entries(scope)
return return
dependancies_by_entry = {} # entry -> dependancies dependancies_by_entry = {} # entry -> dependancies
...@@ -286,6 +288,19 @@ class SimpleAssignmentTypeInferer: ...@@ -286,6 +288,19 @@ class SimpleAssignmentTypeInferer:
entry.type = py_object_type entry.type = py_object_type
if verbose: if verbose:
message(entry.pos, "inferred '%s' to be of type '%s' (default)" % (entry.name, entry.type)) message(entry.pos, "inferred '%s' to be of type '%s' (default)" % (entry.name, entry.type))
#if scope.is_closure_scope:
# fix_closure_entries(scope)
def fix_closure_entries(scope):
"""Temporary work-around to fix field types in the closure class
that were unknown at the time of creation and only determined
during type inference.
"""
closure_entries = scope.scope_class.type.scope.entries
for name, entry in scope.entries.iteritems():
if name in closure_entries:
closure_entry = closure_entries[name]
closure_entry.type = entry.type
def find_spanning_type(type1, type2): def find_spanning_type(type1, type2):
if type1 is type2: if type1 is type2:
......
...@@ -119,22 +119,36 @@ class ResultRefNode(AtomicExprNode): ...@@ -119,22 +119,36 @@ class ResultRefNode(AtomicExprNode):
subexprs = [] subexprs = []
lhs_of_first_assignment = False lhs_of_first_assignment = False
def __init__(self, expression): def __init__(self, expression=None, pos=None, type=None):
self.pos = expression.pos
self.expression = expression self.expression = expression
self.pos = None
if expression is not None:
self.pos = expression.pos
if hasattr(expression, "type"): if hasattr(expression, "type"):
self.type = expression.type self.type = expression.type
if pos is not None:
self.pos = pos
if type is not None:
self.type = type
assert self.pos is not None
def analyse_types(self, env): def analyse_types(self, env):
if self.expression is not None:
self.type = self.expression.type self.type = self.expression.type
def infer_type(self, env): def infer_type(self, env):
if self.expression is not None:
return self.expression.infer_type(env) return self.expression.infer_type(env)
def is_simple(self): def is_simple(self):
return True return True
def result(self): def result(self):
try:
return self.result_code
except AttributeError:
if self.expression is not None:
self.result_code = self.expression.result()
return self.result_code return self.result_code
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
...@@ -258,9 +272,6 @@ class TempResultFromStatNode(ExprNodes.ExprNode): ...@@ -258,9 +272,6 @@ class TempResultFromStatNode(ExprNodes.ExprNode):
# body. Requires a ResultRefNode that it sets up to refer to its # body. Requires a ResultRefNode that it sets up to refer to its
# own temp result. The StatNode must assign a value to the result # own temp result. The StatNode must assign a value to the result
# node, which then becomes the result of this node. # node, which then becomes the result of this node.
#
# This can only be used in/after type analysis.
#
subexprs = [] subexprs = []
child_attrs = ['body'] child_attrs = ['body']
...@@ -272,6 +283,12 @@ class TempResultFromStatNode(ExprNodes.ExprNode): ...@@ -272,6 +283,12 @@ class TempResultFromStatNode(ExprNodes.ExprNode):
self.type = result_ref.type self.type = result_ref.type
self.is_temp = 1 self.is_temp = 1
def analyse_declarations(self, env):
self.body.analyse_declarations(env)
def analyse_types(self, env):
self.body.analyse_expressions(env)
def generate_result_code(self, code): def generate_result_code(self, code):
self.result_ref.result_code = self.result() self.result_ref.result_code = self.result()
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
...@@ -46,7 +46,7 @@ class BasicVisitor(object): ...@@ -46,7 +46,7 @@ class BasicVisitor(object):
if self.access_path: if self.access_path:
print self.access_path[-1][0].pos print self.access_path[-1][0].pos
print self.access_path[-1][0].__dict__ print self.access_path[-1][0].__dict__
raise RuntimeError("Visitor does not accept object: %s" % obj) raise RuntimeError("Visitor %r does not accept object: %s" % (self, obj))
#print "Caching " + cls.__name__ #print "Caching " + cls.__name__
return handler_method return handler_method
...@@ -260,7 +260,7 @@ class VisitorTransform(TreeVisitor): ...@@ -260,7 +260,7 @@ class VisitorTransform(TreeVisitor):
class CythonTransform(VisitorTransform): class CythonTransform(VisitorTransform):
""" """
Certain common conventions and utilitues for Cython transforms. Certain common conventions and utilities for Cython transforms.
- Sets up the context of the pipeline in self.context - Sets up the context of the pipeline in self.context
- Tracks directives in effect in self.current_directives - Tracks directives in effect in self.current_directives
...@@ -352,7 +352,9 @@ class RecursiveNodeReplacer(VisitorTransform): ...@@ -352,7 +352,9 @@ class RecursiveNodeReplacer(VisitorTransform):
else: else:
return node return node
def recursively_replace_node(tree, old_node, new_node):
replace_in = RecursiveNodeReplacer(old_node, new_node)
replace_in(tree)
# Utils # Utils
......
...@@ -23,19 +23,19 @@ cdef extern from "Python.h": ...@@ -23,19 +23,19 @@ cdef extern from "Python.h":
bint PyBytes_CheckExact(object o) bint PyBytes_CheckExact(object o)
# Return true if the object o is a string object, but not an instance of a subtype of the string type. # Return true if the object o is a string object, but not an instance of a subtype of the string type.
object PyBytes_FromString(char *v) bytes PyBytes_FromString(char *v)
# Return value: New reference. # Return value: New reference.
# Return a new string object with the value v on success, and NULL # Return a new string object with the value v on success, and NULL
# on failure. The parameter v must not be NULL; it will not be # on failure. The parameter v must not be NULL; it will not be
# checked. # checked.
object PyBytes_FromStringAndSize(char *v, Py_ssize_t len) bytes PyBytes_FromStringAndSize(char *v, Py_ssize_t len)
# Return value: New reference. # Return value: New reference.
# Return a new string object with the value v and length len on # Return a new string object with the value v and length len on
# success, and NULL on failure. If v is NULL, the contents of the # success, and NULL on failure. If v is NULL, the contents of the
# string are uninitialized. # string are uninitialized.
object PyBytes_FromFormat(char *format, ...) bytes PyBytes_FromFormat(char *format, ...)
# Return value: New reference. # Return value: New reference.
# Take a C printf()-style format string and a variable number of # Take a C printf()-style format string and a variable number of
# arguments, calculate the size of the resulting Python string and # arguments, calculate the size of the resulting Python string and
...@@ -64,7 +64,7 @@ cdef extern from "Python.h": ...@@ -64,7 +64,7 @@ cdef extern from "Python.h":
# format string to be copied as-is to the result string, and any # format string to be copied as-is to the result string, and any
# extra arguments discarded. # extra arguments discarded.
object PyBytes_FromFormatV(char *format, va_list vargs) bytes PyBytes_FromFormatV(char *format, va_list vargs)
# Return value: New reference. # Return value: New reference.
# Identical to PyBytes_FromFormat() except that it takes exactly two arguments. # Identical to PyBytes_FromFormat() except that it takes exactly two arguments.
...@@ -134,7 +134,7 @@ cdef extern from "Python.h": ...@@ -134,7 +134,7 @@ cdef extern from "Python.h":
# *string is set to NULL, a memory exception is set, and -1 is # *string is set to NULL, a memory exception is set, and -1 is
# returned. # returned.
object PyBytes_Format(object format, object args) bytes PyBytes_Format(object format, object args)
# Return value: New reference. Return a new string object from # Return value: New reference. Return a new string object from
# format and args. Analogous to format % args. The args argument # format and args. Analogous to format % args. The args argument
# must be a tuple. # must be a tuple.
...@@ -152,7 +152,7 @@ cdef extern from "Python.h": ...@@ -152,7 +152,7 @@ cdef extern from "Python.h":
# reference-count-neutral; you own the object after the call if # reference-count-neutral; you own the object after the call if
# and only if you owned it before the call.) # and only if you owned it before the call.)
object PyBytes_InternFromString(char *v) bytes PyBytes_InternFromString(char *v)
# Return value: New reference. # Return value: New reference.
# A combination of PyBytes_FromString() and # A combination of PyBytes_FromString() and
# PyBytes_InternInPlace(), returning either a new string object # PyBytes_InternInPlace(), returning either a new string object
......
...@@ -188,16 +188,31 @@ def open_source_from_loader(loader, ...@@ -188,16 +188,31 @@ def open_source_from_loader(loader,
stream = NormalisedNewlineStream(stream) stream = NormalisedNewlineStream(stream)
return stream return stream
def long_literal(value): def str_to_number(value):
if isinstance(value, basestring): # note: this expects a string as input that was accepted by the
# parser already
if len(value) < 2: if len(value) < 2:
value = int(value) value = int(value, 0)
elif value[0] == 0: elif value[0] == '0':
value = int(value, 8) if value[1] in 'xX':
elif value[1] in 'xX': # hex notation ('0x1AF')
value = int(value[2:], 16) value = int(value[2:], 16)
elif value[1] in 'oO':
# Py3 octal notation ('0o136')
value = int(value[2:], 8)
elif value[1] in 'bB':
# Py3 binary notation ('0b101')
value = int(value[2:], 2)
else:
# Py2 octal notation ('0136')
value = int(value, 8)
else: else:
value = int(value) value = int(value, 0)
return value
def long_literal(value):
if isinstance(value, basestring):
value = str_to_number(value)
return not -2**31 <= value < 2**31 return not -2**31 <= value < 2**31
def none_or_sub(s, data): def none_or_sub(s, data):
......
...@@ -51,6 +51,9 @@ EXT_DEP_INCLUDES = [ ...@@ -51,6 +51,9 @@ EXT_DEP_INCLUDES = [
VER_DEP_MODULES = { VER_DEP_MODULES = {
# tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e. # tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e.
# (2,4) : (operator.le, ...) excludes ... when PyVer <= 2.4.x # (2,4) : (operator.le, ...) excludes ... when PyVer <= 2.4.x
(2,5) : (operator.lt, lambda x: x in ['run.any',
'run.all',
]),
(2,4) : (operator.le, lambda x: x in ['run.extern_builtins_T258' (2,4) : (operator.le, lambda x: x in ['run.extern_builtins_T258'
]), ]),
(2,6) : (operator.lt, lambda x: x in ['run.print_function', (2,6) : (operator.lt, lambda x: x in ['run.print_function',
...@@ -786,7 +789,6 @@ if __name__ == '__main__': ...@@ -786,7 +789,6 @@ if __name__ == '__main__':
if sys.version_info[0] >= 3: if sys.version_info[0] >= 3:
options.doctests = False options.doctests = False
options.pyregr = False
if options.with_cython: if options.with_cython:
try: try:
# try if Cython is installed in a Py3 version # try if Cython is installed in a Py3 version
......
...@@ -11,8 +11,10 @@ cascaded_list_unpacking_T467 ...@@ -11,8 +11,10 @@ cascaded_list_unpacking_T467
compile.cpp_operators compile.cpp_operators
cpp_templated_ctypedef cpp_templated_ctypedef
cpp_structs cpp_structs
genexpr_T491
with_statement_module_level_T536 with_statement_module_level_T536
function_as_method_T494 function_as_method_T494
closure_inside_cdef_T554
# CPython regression tests that don't current work: # CPython regression tests that don't current work:
pyregr.test_threadsignals pyregr.test_threadsignals
......
if x:
def h():
pass
_ERRORS = u"""
2:1: def statement not allowed here
"""
def f():
def g():
pass
_ERRORS = u"""
2:1: def statement not allowed here
"""
cdef class VerboseGetItem(object):
cdef object sequence
def __init__(self, seq):
self.sequence = seq
def __getitem__(self, i):
print i
return self.sequence[i] # may raise IndexError
cimport cython
@cython.test_assert_path_exists("//SimpleCallNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def all_item(x):
"""
>>> all_item([1,1,1,1,1])
True
>>> all_item([1,1,1,1,0])
False
>>> all_item([0,1,1,1,0])
False
>>> all(VerboseGetItem([1,1,1,0,0]))
0
1
2
3
False
>>> all_item(VerboseGetItem([1,1,1,0,0]))
0
1
2
3
False
>>> all(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
>>> all_item(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
"""
return all(x)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def all_in_simple_gen(seq):
"""
>>> all_in_simple_gen([1,1,1])
True
>>> all_in_simple_gen([1,1,0])
False
>>> all_in_simple_gen([1,0,1])
False
>>> all_in_simple_gen(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
>>> all_in_simple_gen(VerboseGetItem([1,1,0,1,1]))
0
1
2
False
"""
return all(x for x in seq)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def all_in_simple_gen_scope(seq):
"""
>>> all_in_simple_gen_scope([1,1,1])
True
>>> all_in_simple_gen_scope([1,1,0])
False
>>> all_in_simple_gen_scope([1,0,1])
False
>>> all_in_simple_gen_scope(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
>>> all_in_simple_gen_scope(VerboseGetItem([1,1,0,1,1]))
0
1
2
False
"""
x = 'abc'
result = all(x for x in seq)
assert x == 'abc'
return result
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def all_in_conditional_gen(seq):
"""
>>> all_in_conditional_gen([3,6,9])
False
>>> all_in_conditional_gen([0,3,7])
False
>>> all_in_conditional_gen([1,0,1])
True
>>> all_in_conditional_gen(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
>>> all_in_conditional_gen(VerboseGetItem([1,1,0,1,1]))
0
1
2
3
4
5
True
"""
return all(x%3 for x in seq if x%2 == 1)
mixed_ustring = u'AbcDefGhIjKlmnoP'
lower_ustring = mixed_ustring.lower()
upper_ustring = mixed_ustring.upper()
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//ForFromStatNode')
@cython.test_fail_if_path_exists('//SimpleCallNode',
'//ForInStatNode')
def all_lower_case_characters(unicode ustring):
"""
>>> all_lower_case_characters(mixed_ustring)
False
>>> all_lower_case_characters(upper_ustring)
False
>>> all_lower_case_characters(lower_ustring)
True
"""
return all(uchar.islower() for uchar in ustring)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode",
"//InlinedGeneratorExpressionNode//IfStatNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode",
"//IfStatNode//CoerceToBooleanNode")
def all_in_typed_gen(seq):
"""
>>> all_in_typed_gen([1,1,1])
True
>>> all_in_typed_gen([1,0,0])
False
>>> all_in_typed_gen(VerboseGetItem([1,1,1,1,1]))
0
1
2
3
4
5
True
>>> all_in_typed_gen(VerboseGetItem([1,1,1,1,0]))
0
1
2
3
4
False
"""
cdef int x
return all(x for x in seq)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode",
"//InlinedGeneratorExpressionNode//IfStatNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode",
"//IfStatNode//CoerceToBooleanNode")
def all_in_double_gen(seq):
"""
>>> all(x for L in [[1,1,1],[1,1,1],[1,1,1]] for x in L)
True
>>> all_in_double_gen([[1,1,1],[1,1,1],[1,1,1]])
True
>>> all(x for L in [[1,1,1],[1,1,1],[1,1,0]] for x in L)
False
>>> all_in_double_gen([[1,1,1],[1,1,1],[1,1,0]])
False
>>> all(x for L in [[1,1,1],[0,1,1],[1,1,1]] for x in L)
False
>>> all_in_double_gen([[1,1,1],[0,1,1],[1,1,1]])
False
>>> all_in_double_gen([VerboseGetItem([1,1,1]), VerboseGetItem([1,1,1,1,1])])
0
1
2
3
0
1
2
3
4
5
True
>>> all_in_double_gen([VerboseGetItem([1,1,1]),VerboseGetItem([1,1]),VerboseGetItem([1,1,0])])
0
1
2
3
0
1
2
0
1
2
False
"""
cdef int x
return all(x for L in seq for x in L)
cdef class VerboseGetItem(object):
cdef object sequence
def __init__(self, seq):
self.sequence = seq
def __getitem__(self, i):
print i
return self.sequence[i] # may raise IndexError
cimport cython
@cython.test_assert_path_exists("//SimpleCallNode")
@cython.test_fail_if_path_exists("//ForInStatNode")
def any_item(x):
"""
>>> any_item([0,0,1,0,0])
True
>>> any_item([0,0,0,0,1])
True
>>> any_item([0,0,0,0,0])
False
>>> any(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any_item(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
>>> any_item(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
"""
return any(x)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def any_in_simple_gen(seq):
"""
>>> any_in_simple_gen([0,1,0])
True
>>> any_in_simple_gen([0,0,0])
False
>>> any_in_simple_gen(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any_in_simple_gen(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
"""
return any(x for x in seq)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def any_in_simple_gen_scope(seq):
"""
>>> any_in_simple_gen_scope([0,1,0])
True
>>> any_in_simple_gen_scope([0,0,0])
False
>>> any_in_simple_gen_scope(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any_in_simple_gen_scope(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
"""
x = 'abc'
result = any(x for x in seq)
assert x == 'abc'
return result
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def any_in_conditional_gen(seq):
"""
>>> any_in_conditional_gen([3,6,9])
False
>>> any_in_conditional_gen([0,3,7])
True
>>> any_in_conditional_gen([1,0,1])
True
>>> any_in_conditional_gen(VerboseGetItem([0,0,3,0,0]))
0
1
2
3
4
5
False
>>> any_in_conditional_gen(VerboseGetItem([0,3,0,1,1]))
0
1
2
3
True
"""
return any(x%3 for x in seq if x%2 == 1)
mixed_ustring = u'AbcDefGhIjKlmnoP'
lower_ustring = mixed_ustring.lower()
upper_ustring = mixed_ustring.upper()
@cython.test_assert_path_exists('//PythonCapiCallNode',
'//ForFromStatNode',
"//InlinedGeneratorExpressionNode")
@cython.test_fail_if_path_exists('//SimpleCallNode',
'//ForInStatNode')
def any_lower_case_characters(unicode ustring):
"""
>>> any_lower_case_characters(upper_ustring)
False
>>> any_lower_case_characters(mixed_ustring)
True
>>> any_lower_case_characters(lower_ustring)
True
"""
return any(uchar.islower() for uchar in ustring)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode",
"//InlinedGeneratorExpressionNode//IfStatNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode",
"//IfStatNode//CoerceToBooleanNode")
def any_in_typed_gen(seq):
"""
>>> any_in_typed_gen([0,1,0])
True
>>> any_in_typed_gen([0,0,0])
False
>>> any_in_typed_gen(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any_in_typed_gen(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
"""
cdef int x
return any(x for x in seq)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode",
"//InlinedGeneratorExpressionNode//IfStatNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode")
def any_in_gen_builtin_name(seq):
"""
>>> any_in_gen_builtin_name([0,1,0])
True
>>> any_in_gen_builtin_name([0,0,0])
False
>>> any_in_gen_builtin_name(VerboseGetItem([0,0,1,0,0]))
0
1
2
True
>>> any_in_gen_builtin_name(VerboseGetItem([0,0,0,0,0]))
0
1
2
3
4
5
False
"""
return any(type for type in seq)
@cython.test_assert_path_exists("//ForInStatNode",
"//InlinedGeneratorExpressionNode",
"//InlinedGeneratorExpressionNode//IfStatNode")
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//YieldExprNode",
"//IfStatNode//CoerceToBooleanNode")
def any_in_double_gen(seq):
"""
>>> any(x for L in [[0,0,0],[0,0,1],[0,0,0]] for x in L)
True
>>> any_in_double_gen([[0,0,0],[0,0,1],[0,0,0]])
True
>>> any(x for L in [[0,0,0],[0,0,0],[0,0,0]] for x in L)
False
>>> any_in_double_gen([[0,0,0],[0,0,0],[0,0,0]])
False
>>> any_in_double_gen([VerboseGetItem([0,0,0]), VerboseGetItem([0,0,1,0,0])])
0
1
2
3
0
1
2
True
>>> any_in_double_gen([VerboseGetItem([0,0,0]),VerboseGetItem([0,0]),VerboseGetItem([0,0,0])])
0
1
2
3
0
1
2
0
1
2
3
False
"""
cdef int x
return any(x for L in seq for x in L)
def f(dict d, x=4):
"""
>>> f({1:1, 2:2})
[1, 2]
"""
cdef dict d_new = {}
l = []
for k in d:
d = d_new
l.append(k)
l.sort()
return l
cimport cython
# min()
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def min3(a,b,c):
"""
>>> min3(1,2,3)
1
>>> min3(2,3,1)
1
>>> min3(2,1,3)
1
>>> min3(3,1,2)
1
>>> min3(3,2,1)
1
"""
return min(a,b,c)
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def min3_typed(int a, int b, int c):
"""
>>> min3_typed(1,2,3)
1
>>> min3_typed(2,3,1)
1
>>> min3_typed(2,1,3)
1
>>> min3_typed(3,1,2)
1
>>> min3_typed(3,2,1)
1
"""
return min(a,b,c)
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def literal_min3():
"""
>>> literal_min3()
(1, 1, 1, 1, 1)
"""
return min(1,2,3), min(2,1,3), min(2,3,1), min(3,1,2), min(3,2,1)
# max()
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def max3(a,b,c):
"""
>>> max3(1,2,3)
3
>>> max3(2,3,1)
3
>>> max3(2,1,3)
3
>>> max3(3,1,2)
3
>>> max3(3,2,1)
3
"""
return max(a,b,c)
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def max3_typed(int a, int b, int c):
"""
>>> max3_typed(1,2,3)
3
>>> max3_typed(2,3,1)
3
>>> max3_typed(2,1,3)
3
>>> max3_typed(3,1,2)
3
>>> max3_typed(3,2,1)
3
"""
return max(a,b,c)
@cython.test_assert_path_exists("//CondExprNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def literal_max3():
"""
>>> literal_max3()
(3, 3, 3, 3, 3)
"""
return max(1,2,3), max(2,1,3), max(2,3,1), max(3,1,2), max(3,2,1)
# The arguments in f() are put into the closure one after the other,
# so the reference of 'o' is filled in before the type errors are
# found. This leaves a reference in the closure instance on error
# return, which must be properly ref-counted to facilitate generic
# closure deallocation. In the case of an argument type error, it's
# actually best to just Py_CLEAR() the already handled references, as
# this frees them as early as possible.
# This test doesn't really check the ref-counting itself, it just
# reproduces the problem.
def func_with_typed_args(object o, int i, tuple t, double d):
"""
>>> g = func_with_typed_args(1, 2, (), 3.0)
>>> g()
(1, 2, (), 3.0)
>>> g = func_with_typed_args(1, 'x', (), 3.0)
Traceback (most recent call last):
TypeError: an integer is required
>>> g = func_with_typed_args(1, 2, 3, 3.0)
Traceback (most recent call last):
TypeError: Argument 't' has incorrect type (expected tuple, got int)
"""
def g():
return o, i, t, d
return g
__doc__ = """
>>> Num(13).is_prime()
args (Num(13),) kwds {}
True
>>> Num(13).is_prime(True)
args (Num(13), True) kwds {}
True
>>> Num(15).is_prime(print_factors=True)
args (Num(15),) kwds {'print_factors': True}
3 5
False
"""
def print_args(func):
def f(*args, **kwds):
print "args", args, "kwds", kwds
return func(*args, **kwds)
return f
cdef class Num:
cdef int n
def __init__(self, n):
self.n = n
def __repr__(self):
return "Num(%s)" % self.n
@print_args
def is_prime(self, bint print_factors=False):
if self.n == 2:
return True
elif self.n < 2:
return False
elif self.n % 2 == 0:
if print_factors:
print 2, self.n // 2
cdef int i = 3
while i*i <= self.n:
if self.n % i == 0:
if print_factors:
print i, self.n // i
return False
i += 2
return True
def call_f(x):
"""
>>> call_f(2)
4
"""
return f(x)
cdef f(x): # def here => works fine
def g(y): return y*x # cdef here => compile error
return g(x) # faults@ INCREF(.*cur_scope->.*v_x
#
# closure_tests_1.pyx
#
# Battery of tests for closures in Cython. Based on the collection of
# compiler tests from P423/B629 at Indiana University, Spring 1999 and
# Fall 2000. Special thanks to R. Kent Dybvig, Dan Friedman, Kevin
# Millikin, and everyone else who helped to generate the original
# tests. Converted into a collection of Python/Cython tests by Craig
# Citro.
#
# Note: This set of tests is split (somewhat randomly) into several
# files, simply because putting all the tests in a single file causes
# gcc and g++ to buckle under the load.
#
def g1425():
"""
>>> g1425()
142
"""
if (True):
def g1424():
if (True):
return 122
return (20)+(g1424())
else:
return 10000
def g1432():
"""
>>> g1432()
[0, []]
"""
def g1431():
return [0,[]]
x_1056 = g1431()
if (x_1056):
def g1430():
def g1429():
return (x_1056[0])
def g1428():
return (x_1056[0])
return (g1429())+(g1428())
x_1056[0] = g1430()
return x_1056
def g1435():
"""
>>> g1435()
4000
"""
def g1434():
def g1433(y_1057):
return y_1057
return g1433
return g1434()(4000)
def g1438():
"""
>>> g1438()
1
"""
def g1437():
def g1436(x_1058):
return x_1058
return g1436
f_1059 = g1437()
return (f_1059(0)+1)
def g1441():
"""
>>> g1441()
4
"""
def g1440():
def g1439(y_1060):
return y_1060
return g1439
f_1061 = g1440()
return f_1061(f_1061(4))
def g1446():
"""
>>> g1446()
4
"""
def g1445():
def g1444(f_1063):
return f_1063(f_1063(4))
return g1444
def g1443():
def g1442(y_1062):
return y_1062
return g1442
return g1445()(g1443())
def g1449():
"""
>>> g1449()
9000
"""
def g1448():
a_1064 = 4000
def g1447(b_1065):
return (a_1064)+(b_1065)
return g1447
return g1448()(5000)
def g1454():
"""
>>> g1454()
9000
"""
def g1453():
def g1452():
def g1450(a_1066):
def g1451(b_1067):
return (a_1066)+(b_1067)
return g1451
return g1450
return g1452()(4000)
return g1453()(5000)
def g1459():
"""
>>> g1459()
2
"""
def g1458():
def g1457(f_1069):
return f_1069(f_1069(0))
return g1457
def g1456():
def g1455(x_1068):
return (x_1068+1)
return g1455
return g1458()(g1456())
def g1462():
"""
>>> g1462()
0
"""
x_1072 = 0
def g1461():
def g1460(x_1070):
return x_1070
return g1460
f_1071 = g1461()
a_1075 = f_1071(x_1072)
b_1074 = f_1071(x_1072)
c_1073 = f_1071(x_1072)
return ((a_1075)+(b_1074))+(c_1073)
def g1465():
"""
>>> g1465()
3
"""
x_1080 = 0
y_1079 = 1
z_1078 = 2
def g1464():
def g1463(x_1076):
return x_1076
return g1463
f_1077 = g1464()
a_1083 = f_1077(x_1080)
b_1082 = f_1077(y_1079)
c_1081 = f_1077(z_1078)
return ((a_1083)+(b_1082))+(c_1081)
def g1468():
"""
>>> g1468()
0
"""
def g1467():
def g1466(x_1085, y_1084):
return x_1085
return g1466
f_1086 = g1467()
a_1087 = f_1086(0, 1)
return f_1086(a_1087, a_1087)
def g1471():
"""
>>> g1471()
0
"""
x_1094 = 0
y_1093 = 1
z_1092 = 2
def g1470():
def g1469(x_1090, y_1089, z_1088):
return x_1090
return g1469
f_1091 = g1470()
a_1097 = f_1091(x_1094, y_1093, z_1092)
b_1096 = y_1093
c_1095 = z_1092
return f_1091(a_1097, b_1096, c_1095)
def g1474():
"""
>>> g1474()
3
"""
def g1473():
def g1472(a_1101, b_1100, c_1099, d_1098):
return (a_1101)+(d_1098)
return g1472
f_1102 = g1473()
return f_1102(0, 1, 2, 3)
def g1478():
"""
>>> g1478()
3
"""
def g1477():
def g1476(x_1103):
return x_1103
return g1476
f_1104 = g1477()
def g1475():
a_1107 = 0
b_1106 = 1
c_1105 = 2
return (f_1104(a_1107))+((f_1104(b_1106))+(f_1104(c_1105)))
return (f_1104(0))+(g1475())
def g1483():
"""
>>> g1483()
"""
a_1108 = 0
def g1482():
def g1481():
return 0
return g1481
a_1110 = g1482()
def g1480():
def g1479():
return 11
return g1479
b_1109 = g1480()
a_1110 = 11
def g1486():
"""
>>> g1486()
"""
a_1111 = 0
def g1485():
def g1484():
a_1113 = 0
return g1484
a_1113 = g1485()
b_1112 = 11
return a_1113()
def g1491():
"""
>>> g1491()
0
"""
def g1490():
def g1489():
return 0
return g1489
a_1115 = g1490()
def g1488():
def g1487():
return 11
return g1487
b_1114 = g1488()
return a_1115()
def g1494():
"""
>>> g1494()
2
"""
def g1493():
x_1116 = 1
def g1492(y_1117):
return (x_1116)+(y_1117)
return g1492
f_1118 = g1493()
x_1119 = 0
return f_1118(f_1118(x_1119))
def g1501():
"""
>>> g1501()
3050
"""
def g1500():
def g1499():
def g1498(x_1121):
return (x_1121)+(50)
return g1498
t_1122 = g1499()
def g1497(f_1123):
return t_1122(f_1123(1000))
return g1497
def g1496():
def g1495(y_1120):
return (y_1120)+(2000)
return g1495
return g1500()(g1496())
def g1508():
"""
>>> g1508()
60
"""
def g1507():
def g1506():
def g1505():
def g1502(a_1124):
def g1503(b_1125):
def g1504(c_1126):
return (a_1124)+((b_1125)+(c_1126))
return g1504
return g1503
return g1502
return g1505()(10)
return g1506()(20)
return g1507()(30)
def g1513():
"""
>>> g1513()
5
"""
def g1512():
def g1509(b_1127):
def g1511():
def g1510(a_1128):
return (b_1127)+(a_1128)
return g1510
return g1511()(2)
return g1509
return g1512()(3)
def g1518():
"""
>>> g1518()
5
"""
def g1517():
def g1516(f_1130):
return f_1130(f_1130(5))
return g1516
def g1515():
def g1514(x_1129):
return x_1129
return g1514
return g1517()(g1515())
def g1523():
"""
>>> g1523()
8000
"""
def g1522():
def g1521():
def g1520(x_1131):
return (x_1131)+(3000)
return g1520
f_1132 = g1521()
def g1519(y_1133):
return f_1132(f_1132(y_1133))
return g1519
return g1522()(2000)
#
# closure_tests_2.pyx
#
# Battery of tests for closures in Cython. Based on the collection of
# compiler tests from P423/B629 at Indiana University, Spring 1999 and
# Fall 2000. Special thanks to R. Kent Dybvig, Dan Friedman, Kevin
# Millikin, and everyone else who helped to generate the original
# tests. Converted into a collection of Python/Cython tests by Craig
# Citro.
#
# Note: This set of tests is split (somewhat randomly) into several
# files, simply because putting all the tests in a single file causes
# gcc and g++ to buckle under the load.
#
def g1526():
"""
>>> g1526()
2
"""
x_1134 = 0
def g1525():
x_1136 = 1
z_1135 = x_1134
def g1524(y_1137):
return (x_1136)+((z_1135)+(y_1137))
return g1524
f_1138 = g1525()
return f_1138(f_1138(x_1134))
def g1535():
"""
>>> g1535()
3050
"""
def g1534():
def g1533():
def g1531(t_1141):
def g1532(f_1142):
return t_1141(f_1142(1000))
return g1532
return g1531
def g1530():
def g1529(x_1140):
return (x_1140)+(50)
return g1529
return g1533()(g1530())
def g1528():
def g1527(y_1139):
return (y_1139)+(2000)
return g1527
return g1534()(g1528())
def g1540():
"""
>>> g1540()
2050
"""
def g1539():
t_1143 = 50
def g1538(f_1144):
return (t_1143)+(f_1144())
return g1538
def g1537():
def g1536():
return 2000
return g1536
return g1539()(g1537())
def g1547():
"""
>>> g1547()
2050
"""
def g1546():
def g1545():
def g1543(t_1145):
def g1544(f_1146):
return (t_1145)+(f_1146())
return g1544
return g1543
return g1545()(50)
def g1542():
def g1541():
return 2000
return g1541
return g1546()(g1542())
def g1550():
"""
>>> g1550()
700
"""
def g1549():
x_1147 = 300
def g1548(y_1148):
return (x_1147)+(y_1148)
return g1548
return g1549()(400)
def g1553():
"""
>>> g1553()
0
"""
x_1152 = 3
def g1552():
def g1551(x_1150, y_1149):
return x_1150
return g1551
f_1151 = g1552()
if (f_1151(0, 0)):
return f_1151(f_1151(0, 0), x_1152)
else:
return 0
def g1562():
"""
>>> g1562()
False
"""
def g1561():
def g1556(x_1153):
def g1560():
def g1559():
return isinstance(x_1153, list)
if (g1559()):
def g1558():
def g1557():
return (x_1153[0])
return (g1557() == 0)
return (not g1558())
else:
return False
if (g1560()):
return x_1153
else:
return False
return g1556
f_1154 = g1561()
def g1555():
def g1554():
return [0,[]]
return [0,g1554()]
return f_1154(g1555())
def g1570():
"""
>>> g1570()
False
"""
def g1569():
def g1563(x_1155):
def g1568():
if (x_1155):
def g1567():
def g1566():
return isinstance(x_1155, list)
if (g1566()):
def g1565():
def g1564():
return (x_1155[0])
return (g1564() == 0)
return (not g1565())
else:
return False
return (not g1567())
else:
return False
if (g1568()):
return x_1155
else:
return False
return g1563
f_1156 = g1569()
return f_1156(0)
def g1575():
"""
>>> g1575()
[]
"""
def g1574():
def g1571(x_1157):
def g1573():
def g1572():
return isinstance(x_1157, list)
if (g1572()):
return True
else:
return (x_1157 == [])
if (g1573()):
return x_1157
else:
return []
return g1571
f_1158 = g1574()
return f_1158(0)
def g1578():
"""
>>> g1578()
4
"""
y_1159 = 4
def g1577():
def g1576(y_1160):
return y_1160
return g1576
f_1161 = g1577()
return f_1161(f_1161(y_1159))
def g1581():
"""
>>> g1581()
0
"""
y_1162 = 4
def g1580():
def g1579(x_1164, y_1163):
return 0
return g1579
f_1165 = g1580()
return f_1165(f_1165(y_1162, y_1162), f_1165(y_1162, y_1162))
def g1584():
"""
>>> g1584()
0
"""
y_1166 = 4
def g1583():
def g1582(x_1168, y_1167):
return 0
return g1582
f_1169 = g1583()
return f_1169(f_1169(y_1166, y_1166), f_1169(y_1166, f_1169(y_1166, y_1166)))
def g1587():
"""
>>> g1587()
0
"""
y_1170 = 4
def g1586():
def g1585(x_1172, y_1171):
return 0
return g1585
f_1173 = g1586()
return f_1173(f_1173(y_1170, f_1173(y_1170, y_1170)), f_1173(y_1170, f_1173(y_1170, y_1170)))
def g1594():
"""
>>> g1594()
4
"""
def g1593():
def g1588(y_1174):
def g1592():
def g1591(f_1176):
return f_1176(f_1176(y_1174))
return g1591
def g1590():
def g1589(y_1175):
return y_1175
return g1589
return g1592()(g1590())
return g1588
return g1593()(4)
def g1598():
"""
>>> g1598()
23
"""
def g1597():
def g1596(x_1177):
return x_1177
return g1596
f_1178 = g1597()
def g1595():
if (False):
return 1
else:
return f_1178(22)
return (g1595()+1)
def g1603():
"""
>>> g1603()
22
"""
def g1602():
def g1601(x_1179):
return x_1179
return g1601
f_1180 = g1602()
def g1600():
def g1599():
return 23 == 0
return f_1180(g1599())
if (g1600()):
return 1
else:
return 22
def g1611():
"""
>>> g1611()
5061
"""
def g1610():
def g1609(x_1182):
if (x_1182):
return (not x_1182)
else:
return x_1182
return g1609
f_1185 = g1610()
def g1608():
def g1607(x_1181):
return (10)*(x_1181)
return g1607
f2_1184 = g1608()
x_1183 = 23
def g1606():
def g1605():
def g1604():
return x_1183 == 0
return f_1185(g1604())
if (g1605()):
return 1
else:
return (x_1183)*(f2_1184((x_1183-1)))
return (g1606()+1)
def g1614():
"""
>>> g1614()
1
"""
def g1613():
def g1612():
return 0
return g1612
f_1186 = g1613()
x_1187 = f_1186()
return 1
def g1617():
"""
>>> g1617()
1
"""
def g1616():
def g1615():
return 0
return g1615
f_1188 = g1616()
f_1188()
return 1
def g1620():
"""
>>> g1620()
4
"""
def g1619():
def g1618(x_1189):
return x_1189
return g1618
f_1190 = g1619()
if (True):
f_1190(3)
return 4
else:
return 5
def g1623():
"""
>>> g1623()
6
"""
def g1622():
def g1621(x_1191):
return x_1191
return g1621
f_1192 = g1622()
(f_1192(4)) if (True) else (5)
return 6
def g1627():
"""
>>> g1627()
120
"""
def g1626():
def g1624(fact_1195, n_1194, acc_1193):
def g1625():
return n_1194 == 0
if (g1625()):
return acc_1193
else:
return fact_1195(fact_1195, (n_1194-1), (n_1194)*(acc_1193))
return g1624
fact_1196 = g1626()
return fact_1196(fact_1196, 5, 1)
def g1632():
"""
>>> g1632()
144
"""
def g1631():
def g1628(b_1199, c_1198, a_1197):
b_1203 = (b_1199)+(a_1197)
def g1630():
def g1629():
a_1201 = (b_1199)+(b_1199)
c_1200 = (c_1198)+(c_1198)
return (a_1201)+(a_1201)
return (a_1197)+(g1629())
a_1202 = g1630()
return (a_1202)*(a_1202)
return g1628
return g1631()(2, 3, 4)
def g1639():
"""
>>> g1639()
3
"""
def g1638():
def g1636(x_1204):
def g1637():
return x_1204()
return g1637
return g1636
f_1205 = g1638()
def g1635():
def g1634():
def g1633():
return 3
return g1633
return f_1205(g1634())
return g1635()()
def g1646():
"""
>>> g1646()
3628800
"""
def g1645():
def g1643(x_1207):
def g1644():
return x_1207 == 0
if (g1644()):
return 1
else:
return (x_1207)*(f_1206((x_1207)-(1)))
return g1643
f_1206 = g1645()
q_1208 = 17
def g1642():
def g1640(a_1209):
q_1208 = 10
def g1641():
return a_1209(q_1208)
return g1641
return g1640
g_1210 = g1642()
return g_1210(f_1206)()
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
cimport cython
class SomeNumber(object):
def __init__(self, n):
self._n = n
def __repr__(self):
return "SomeNumber(%s)" % self._n
@cython.binding(True)
def add_to_func(self, x):
"""
>>> add_to_func(SomeNumber(2), 5)
7
>>> SomeNumber(3).add_to(10)
13
>>> SomeNumber.add_to(SomeNumber(22), 7)
29
"""
return self._n + x
@cython.binding(False)
def new_num(n):
"""
>>> new_num(11)
SomeNumber(11)
>>> SomeNumber.new(11)
SomeNumber(11)
>>> SomeNumber(3).new(11)
SomeNumber(11)
"""
return SomeNumber(n)
SomeNumber.add_to = add_to_func
SomeNumber.new = new_num
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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