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,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:
......
......@@ -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):
......
......@@ -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,
......
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