Commit a72407b4 authored by Robert Bradshaw's avatar Robert Bradshaw

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.
parent a5e1b89a
...@@ -238,6 +238,9 @@ class CCodeWriter: ...@@ -238,6 +238,9 @@ class CCodeWriter:
def put_var_decref(self, entry): def put_var_decref(self, entry):
if entry.type.is_pyobject: if entry.type.is_pyobject:
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)) self.putln("Py_DECREF(%s);" % self.entry_as_pyobject(entry))
def put_var_decref_clear(self, entry): def put_var_decref_clear(self, entry):
......
...@@ -1422,6 +1422,11 @@ class CDeclaratorNode(Node): ...@@ -1422,6 +1422,11 @@ class CDeclaratorNode(Node):
# CNameDeclaratorNode of the name being declared # CNameDeclaratorNode of the name being declared
# and type is the type it is being declared as. # and type is the type it is being declared as.
# #
def analyse_expressions(self, env):
pass
def generate_execution_code(self, env):
pass pass
...@@ -1430,8 +1435,28 @@ class CNameDeclaratorNode(CDeclaratorNode): ...@@ -1430,8 +1435,28 @@ class CNameDeclaratorNode(CDeclaratorNode):
# cname string or None C name, if specified # cname string or None C name, if specified
def analyse(self, base_type, env): def analyse(self, base_type, env):
self.type = base_type
return self, 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): class CPtrDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode # base CDeclaratorNode
...@@ -1443,6 +1468,11 @@ class CPtrDeclaratorNode(CDeclaratorNode): ...@@ -1443,6 +1468,11 @@ class CPtrDeclaratorNode(CDeclaratorNode):
ptr_type = PyrexTypes.c_ptr_type(base_type) ptr_type = PyrexTypes.c_ptr_type(base_type)
return self.base.analyse(ptr_type, env) 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): class CArrayDeclaratorNode(CDeclaratorNode):
# base CDeclaratorNode # base CDeclaratorNode
...@@ -1625,10 +1655,12 @@ class CVarDefNode(StatNode): ...@@ -1625,10 +1655,12 @@ class CVarDefNode(StatNode):
cname = cname, visibility = self.visibility, is_cdef = 1) cname = cname, visibility = self.visibility, is_cdef = 1)
def analyse_expressions(self, env): def analyse_expressions(self, env):
pass for declarator in self.declarators:
declarator.analyse_expressions(env)
def generate_execution_code(self, code): def generate_execution_code(self, code):
pass for declarator in self.declarators:
declarator.generate_execution_code(code)
class CStructOrUnionDefNode(StatNode): class CStructOrUnionDefNode(StatNode):
...@@ -1844,6 +1876,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1844,6 +1876,7 @@ class FuncDefNode(StatNode, BlockNode):
class CFuncDefNode(FuncDefNode): class CFuncDefNode(FuncDefNode):
# C function definition. # C function definition.
# #
# modifiers 'inline ' or ''
# visibility 'private' or 'public' or 'extern' # visibility 'private' or 'public' or 'extern'
# base_type CBaseTypeNode # base_type CBaseTypeNode
# declarator CDeclaratorNode # declarator CDeclaratorNode
...@@ -1900,8 +1933,9 @@ class CFuncDefNode(FuncDefNode): ...@@ -1900,8 +1933,9 @@ class CFuncDefNode(FuncDefNode):
storage_class = "%s " % Naming.extern_c_macro storage_class = "%s " % Naming.extern_c_macro
else: else:
storage_class = "static " storage_class = "static "
code.putln("%s%s {" % ( code.putln("%s%s%s {" % (
storage_class, storage_class,
self.modifiers,
header)) header))
def generate_argument_declarations(self, env, code): def generate_argument_declarations(self, env, code):
......
...@@ -1396,7 +1396,7 @@ def p_opt_cname(s): ...@@ -1396,7 +1396,7 @@ def p_opt_cname(s):
cname = None cname = None
return cname 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 # If empty is true, the declarator must be
# empty, otherwise we don't care. # empty, otherwise we don't care.
# If cmethod_flag is true, then if this declarator declares # 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): ...@@ -1404,12 +1404,12 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0):
pos = s.position() pos = s.position()
if s.sy == '*': if s.sy == '*':
s.next() 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, result = Nodes.CPtrDeclaratorNode(pos,
base = base) base = base)
elif s.sy == '**': # scanner returns this as a single token elif s.sy == '**': # scanner returns this as a single token
s.next() 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, result = Nodes.CPtrDeclaratorNode(pos,
base = Nodes.CPtrDeclaratorNode(pos, base = Nodes.CPtrDeclaratorNode(pos,
base = base)) base = base))
...@@ -1430,8 +1430,12 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0): ...@@ -1430,8 +1430,12 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0):
else: else:
name = "" name = ""
cname = None cname = None
if s.sy == '=' and assignable:
s.next()
rhs = p_simple_expr(s)
else: rhs = None
result = Nodes.CNameDeclaratorNode(pos, result = Nodes.CNameDeclaratorNode(pos,
name = name, cname = cname) name = name, cname = cname, rhs = rhs)
while s.sy in ('[', '('): while s.sy in ('[', '('):
if s.sy == '[': if s.sy == '[':
s.next() s.next()
...@@ -1652,10 +1656,18 @@ def p_visibility(s, prev_visibility): ...@@ -1652,10 +1656,18 @@ def p_visibility(s, prev_visibility):
s.next() s.next()
return visibility 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'): def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
cmethod_flag = level in ('c_class', 'c_class_pxd') cmethod_flag = level in ('c_class', 'c_class_pxd')
modifiers = p_c_modifiers(s)
base_type = p_c_base_type(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 s.sy == ':':
if level not in ('module', 'c_class'): if level not in ('module', 'c_class'):
s.error("C function definition not allowed here") s.error("C function definition not allowed here")
...@@ -1664,7 +1676,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'): ...@@ -1664,7 +1676,8 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
visibility = visibility, visibility = visibility,
base_type = base_type, base_type = base_type,
declarator = declarator, declarator = declarator,
body = suite) body = suite,
modifiers = modifiers)
else: else:
if level == 'module_pxd' and visibility <> 'extern': if level == 'module_pxd' and visibility <> 'extern':
error(pos, error(pos,
...@@ -1674,7 +1687,7 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'): ...@@ -1674,7 +1687,7 @@ def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
s.next() s.next()
if s.sy == 'NEWLINE': if s.sy == 'NEWLINE':
break break
declarator = p_c_declarator(s, cmethod_flag = cmethod_flag) declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, assignable = 1)
declarators.append(declarator) declarators.append(declarator)
s.expect_newline("Syntax error in C variable declaration") s.expect_newline("Syntax error in C variable declaration")
result = Nodes.CVarDefNode(pos, result = Nodes.CVarDefNode(pos,
......
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