Inline keyword for cdef functions, variable assignment on declaration (+optimization)
authorRobert Bradshaw <robertwb@math.washington.edu>
Tue, 27 Feb 2007 11:46:35 +0000 (03:46 -0800)
committerRobert Bradshaw <robertwb@math.washington.edu>
Tue, 27 Feb 2007 11:46:35 +0000 (03:46 -0800)
"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
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py

index 08f186cc8b22d320866c1390c7801a58a4299069..e75e4aaa7214ca048248d28c8248924ed3b5a5bc 100644 (file)
@@ -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:
index cfcb56be9c7104dcb6a680f6f1b8614a03058930..b950a5ca70b59fd93caab2422c6b997d04cb7d50 100644 (file)
@@ -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):
index c75ebee79652ca4cf24f39d53f94335ecf6acebd..d4cd052a2df289483c8080a5d726eab064514756 100644 (file)
@@ -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,