From a72407b4fff57f0b8a78a08af3b70e693186247c Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Tue, 27 Feb 2007 03:46:35 -0800 Subject: [PATCH] Inline keyword for cdef functions, variable assignment on declaration (+optimization) "cdef inline foo()" now valid, and will place inline in the resulting c code "cdef o = expr" and "cdef type x = expr" now valid. This may not seem like a huge change, but it ended up requiring quite a bit of work. The variables are still all declared at the top, but the assignment takes place at the specified line in the code. If an assignment is made at declaration, the variable is initalized to 0 rather than None (also skipping an INCREF) and Py_XDECREF is used on exiting the function (in case an error occured before the actual value was calculated). Hence these variables MUST NOT be used before they are defined or it will probably segfault. --- Cython/Compiler/Code.py | 5 ++++- Cython/Compiler/Nodes.py | 42 ++++++++++++++++++++++++++++++++++---- Cython/Compiler/Parsing.py | 27 +++++++++++++++++------- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index 08f186cc..e75e4aaa 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -238,7 +238,10 @@ class CCodeWriter: def put_var_decref(self, entry): if entry.type.is_pyobject: - self.putln("Py_DECREF(%s);" % self.entry_as_pyobject(entry)) + if entry.init_to_none is False: + self.putln("Py_XDECREF(%s);" % self.entry_as_pyobject(entry)) + else: + self.putln("Py_DECREF(%s);" % self.entry_as_pyobject(entry)) def put_var_decref_clear(self, entry): if entry.type.is_pyobject: diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index cfcb56be..b950a5ca 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -1422,7 +1422,12 @@ class CDeclaratorNode(Node): # CNameDeclaratorNode of the name being declared # and type is the type it is being declared as. # - pass + + def analyse_expressions(self, env): + pass + + def generate_execution_code(self, env): + pass class CNameDeclaratorNode(CDeclaratorNode): @@ -1430,8 +1435,28 @@ class CNameDeclaratorNode(CDeclaratorNode): # cname string or None C name, if specified def analyse(self, base_type, env): + self.type = base_type return self, base_type + + def analyse_expressions(self, env): + self.entry = env.lookup(self.name) + if self.rhs is not None: + if self.type.is_pyobject: + self.entry.init_to_none = False + self.entry.init = 0 + self.rhs.analyse_types(env) + self.rhs = self.rhs.coerce_to(self.type, env) + self.rhs.allocate_temps(env) + self.rhs.release_temp(env) + def generate_execution_code(self, code): + if self.rhs is not None: + self.rhs.generate_evaluation_code(code) + if self.type.is_pyobject: + self.rhs.make_owned_reference(code) + code.putln('%s = %s;' % (self.entry.cname, self.rhs.result_as(self.entry.type))) + self.rhs.generate_post_assignment_code(code) + code.putln() class CPtrDeclaratorNode(CDeclaratorNode): # base CDeclaratorNode @@ -1443,6 +1468,11 @@ class CPtrDeclaratorNode(CDeclaratorNode): ptr_type = PyrexTypes.c_ptr_type(base_type) return self.base.analyse(ptr_type, env) + def analyse_expressions(self, env): + self.base.analyse_expressions(env) + + def generate_execution_code(self, env): + self.base.generate_execution_code(env) class CArrayDeclaratorNode(CDeclaratorNode): # base CDeclaratorNode @@ -1625,10 +1655,12 @@ class CVarDefNode(StatNode): cname = cname, visibility = self.visibility, is_cdef = 1) def analyse_expressions(self, env): - pass + for declarator in self.declarators: + declarator.analyse_expressions(env) def generate_execution_code(self, code): - pass + for declarator in self.declarators: + declarator.generate_execution_code(code) class CStructOrUnionDefNode(StatNode): @@ -1844,6 +1876,7 @@ class FuncDefNode(StatNode, BlockNode): class CFuncDefNode(FuncDefNode): # C function definition. # + # modifiers 'inline ' or '' # visibility 'private' or 'public' or 'extern' # base_type CBaseTypeNode # declarator CDeclaratorNode @@ -1900,8 +1933,9 @@ class CFuncDefNode(FuncDefNode): storage_class = "%s " % Naming.extern_c_macro else: storage_class = "static " - code.putln("%s%s {" % ( + code.putln("%s%s%s {" % ( storage_class, + self.modifiers, header)) def generate_argument_declarations(self, env, code): diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index c75ebee7..d4cd052a 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -1396,7 +1396,7 @@ def p_opt_cname(s): cname = None return cname -def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0): +def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0 , assignable = 0): # If empty is true, the declarator must be # empty, otherwise we don't care. # If cmethod_flag is true, then if this declarator declares @@ -1404,12 +1404,12 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0): pos = s.position() if s.sy == '*': s.next() - base = p_c_declarator(s, empty, is_type, cmethod_flag) + base = p_c_declarator(s, empty, is_type, cmethod_flag, assignable) result = Nodes.CPtrDeclaratorNode(pos, base = base) elif s.sy == '**': # scanner returns this as a single token s.next() - base = p_c_declarator(s, empty, is_type, cmethod_flag) + base = p_c_declarator(s, empty, is_type, cmethod_flag, assignable) result = Nodes.CPtrDeclaratorNode(pos, base = Nodes.CPtrDeclaratorNode(pos, base = base)) @@ -1430,8 +1430,12 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0): else: name = "" cname = None + if s.sy == '=' and assignable: + s.next() + rhs = p_simple_expr(s) + else: rhs = None result = Nodes.CNameDeclaratorNode(pos, - name = name, cname = cname) + name = name, cname = cname, rhs = rhs) while s.sy in ('[', '('): if s.sy == '[': s.next() @@ -1651,11 +1655,19 @@ def p_visibility(s, prev_visibility): % (prev_visibility, visibility)) s.next() return visibility + +def p_c_modifiers(s): + if s.systring in ('inline', ): + modifier = s.systring + s.next() + return modifier + ' ' + p_c_modifiers(s) + return "" def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'): cmethod_flag = level in ('c_class', 'c_class_pxd') + modifiers = p_c_modifiers(s) base_type = p_c_base_type(s) - declarator = p_c_declarator(s, cmethod_flag = cmethod_flag) + declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1) if s.sy == ':': if level not in ('module', 'c_class'): s.error("C function definition not allowed here") @@ -1664,7 +1676,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'): visibility = visibility, base_type = base_type, declarator = declarator, - body = suite) + body = suite, + modifiers = modifiers) else: if level == 'module_pxd' and visibility <> 'extern': error(pos, @@ -1674,7 +1687,7 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'): s.next() if s.sy == 'NEWLINE': break - declarator = p_c_declarator(s, cmethod_flag = cmethod_flag) + declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1) declarators.append(declarator) s.expect_newline("Syntax error in C variable declaration") result = Nodes.CVarDefNode(pos, -- 2.26.2