Commit 70b5652a authored by Vitja Makarov's avatar Vitja Makarov

Support class closures and nested classes.

Disable some pyregr tests. As side effect this seems to solve ticket #537
parent c1ac5089
...@@ -1177,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1177,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode):
def create_local_scope(self, env): def create_local_scope(self, env):
genv = env genv = env
while genv.is_py_class_scope or genv.is_c_class_scope: while genv.is_py_class_scope or genv.is_c_class_scope:
genv = env.outer_scope genv = genv.outer_scope
if self.needs_closure: if self.needs_closure:
lenv = ClosureScope(name=self.entry.name, lenv = ClosureScope(name=self.entry.name,
outer_scope = genv, outer_scope = genv,
...@@ -1255,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1255,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_function_header(code, self.generate_function_header(code,
with_pymethdef = with_pymethdef) with_pymethdef = with_pymethdef)
# ----- Local variable declarations # ----- Local variable declarations
# Find function scope
cenv = env
while cenv.is_py_class_scope or cenv.is_c_class_scope:
cenv = cenv.outer_scope
if lenv.is_closure_scope: if lenv.is_closure_scope:
code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname)) code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
code.putln(";") code.putln(";")
elif env.is_closure_scope: elif cenv.is_closure_scope:
code.put(env.scope_class.type.declaration_code(Naming.outer_scope_cname)) code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
code.putln(";") code.putln(";")
self.generate_argument_declarations(lenv, code) self.generate_argument_declarations(lenv, code)
for entry in lenv.var_entries: for entry in lenv.var_entries:
...@@ -1310,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1310,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode):
code.putln("}") code.putln("}")
code.put_gotref(Naming.cur_scope_cname) code.put_gotref(Naming.cur_scope_cname)
# Note that it is unsafe to decref the scope at this point. # Note that it is unsafe to decref the scope at this point.
if env.is_closure_scope: if cenv.is_closure_scope:
code.putln("%s = (%s)%s;" % ( code.putln("%s = (%s)%s;" % (
outer_scope_cname, outer_scope_cname,
env.scope_class.type.declaration_code(''), cenv.scope_class.type.declaration_code(''),
Naming.self_cname)) Naming.self_cname))
if self.needs_closure: if self.needs_closure:
# inner closures own a reference to their outer parent # inner closures own a reference to their outer parent
code.put_incref(outer_scope_cname, env.scope_class.type) code.put_incref(outer_scope_cname, cenv.scope_class.type)
code.put_giveref(outer_scope_cname) code.put_giveref(outer_scope_cname)
# ----- Trace function call # ----- Trace function call
if profile: if profile:
...@@ -2211,18 +2215,21 @@ class DefNode(FuncDefNode): ...@@ -2211,18 +2215,21 @@ class DefNode(FuncDefNode):
def synthesize_assignment_node(self, env): def synthesize_assignment_node(self, env):
import ExprNodes import ExprNodes
if env.is_py_class_scope: genv = env
rhs = ExprNodes.PyCFunctionNode(self.pos, while genv.is_py_class_scope or genv.is_c_class_scope:
pymethdef_cname = self.entry.pymethdef_cname) genv = genv.outer_scope
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
elif env.is_closure_scope: if genv.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode( rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname) self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else: else:
rhs = ExprNodes.PyCFunctionNode( rhs = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding']) self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding'])
if env.is_py_class_scope:
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
self.assmt = SingleAssignmentNode(self.pos, self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name), lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs) rhs = rhs)
...@@ -3036,8 +3043,8 @@ class PyClassDefNode(ClassDefNode): ...@@ -3036,8 +3043,8 @@ class PyClassDefNode(ClassDefNode):
def create_scope(self, env): def create_scope(self, env):
genv = env genv = env
while env.is_py_class_scope or env.is_c_class_scope: while genv.is_py_class_scope or genv.is_c_class_scope:
env = env.outer_scope genv = genv.outer_scope
cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv) cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
return cenv return cenv
......
...@@ -1325,7 +1325,7 @@ class CreateClosureClasses(CythonTransform): ...@@ -1325,7 +1325,7 @@ 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 = "%s%s" % (Naming.closure_class_prefix, node.entry.cname) as_name = '%s_%s' % (target_module_scope.next_id(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,
...@@ -1334,11 +1334,15 @@ class CreateClosureClasses(CythonTransform): ...@@ -1334,11 +1334,15 @@ class CreateClosureClasses(CythonTransform):
class_scope = entry.type.scope class_scope = entry.type.scope
class_scope.is_internal = True class_scope.is_internal = True
class_scope.directives = {'final': True} class_scope.directives = {'final': True}
if node.entry.scope.is_closure_scope:
cscope = node.entry.scope
while cscope.is_py_class_scope or cscope.is_c_class_scope:
cscope = cscope.outer_scope
if cscope.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? name=Naming.outer_scope_cname, # this could conflict?
cname=Naming.outer_scope_cname, cname=Naming.outer_scope_cname,
type=node.entry.scope.scope_class.type, type=cscope.scope_class.type,
is_cdef=True) is_cdef=True)
entries = func_scope.entries.items() entries = func_scope.entries.items()
entries.sort() entries.sort()
......
...@@ -1740,7 +1740,7 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -1740,7 +1740,7 @@ def p_statement(s, ctx, first_statement = 0):
s.level = ctx.level s.level = ctx.level
return p_def_statement(s, decorators) return p_def_statement(s, decorators)
elif s.sy == 'class': elif s.sy == 'class':
if ctx.level != 'module': if ctx.level not in ('module', 'function', 'class', 'other'):
s.error("class definition not allowed here") s.error("class definition not allowed here")
return p_class_statement(s, decorators) return p_class_statement(s, decorators)
elif s.sy == 'include': elif s.sy == 'include':
......
...@@ -23,6 +23,8 @@ closure_class_T596 ...@@ -23,6 +23,8 @@ closure_class_T596
pyregr.test_threadsignals pyregr.test_threadsignals
pyregr.test_module pyregr.test_module
pyregr.test_capi pyregr.test_capi
pyregr.test_socket
pyregr.test_threading
# CPython regression tests that don't make sense # CPython regression tests that don't make sense
pyregr.test_gdb pyregr.test_gdb
......
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