Commit af626302 authored by Robert Bradshaw's avatar Robert Bradshaw

Add indirection to closure variables

parent 4510e2ef
......@@ -200,6 +200,8 @@ class CCodeWriter:
def put_var_declaration(self, entry, static = 0, dll_linkage = None,
definition = True):
#print "Code.put_var_declaration:", entry.name, "definition =", definition ###
if entry.in_closure:
return
visibility = entry.visibility
if visibility == 'private' and not definition:
#print "...private and not definition, skipping" ###
......
......@@ -72,7 +72,8 @@ optional_args_cname = pyrex_prefix + "optional_args"
no_opt_args = pyrex_prefix + "no_opt_args"
import_star = pyrex_prefix + "import_star"
import_star_set = pyrex_prefix + "import_star_set"
scope_obj_cname = pyrex_prefix + "scope"
cur_scope_cname = pyrex_prefix + "cur_scope"
enc_scope_cname = pyrex_prefix + "enc_scope"
line_c_macro = "__LINE__"
......
......@@ -10,7 +10,7 @@ import Naming
import PyrexTypes
import TypeSlots
from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
from Symtab import ModuleScope, LocalScope, PersistentLocalScope, \
from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
StructOrUnionScope, PyClassScope, CClassScope
from Cython.Utils import open_new_file, replace_suffix, EncodedString
import Options
......@@ -810,7 +810,7 @@ class FuncDefNode(StatNode, BlockNode):
while env.is_py_class_scope or env.is_c_class_scope:
env = env.outer_scope
if self.needs_closure:
lenv = PersistentLocalScope(name = self.entry.name, outer_scope = genv)
lenv = GeneratorLocalScope(name = self.entry.name, outer_scope = genv)
else:
lenv = LocalScope(name = self.entry.name, outer_scope = genv)
lenv.return_type = self.return_type
......@@ -842,7 +842,10 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_function_header(code,
with_pymethdef = env.is_py_class_scope)
# ----- Local variable declarations
lenv.mangle_closure_cnames(Naming.cur_scope_cname)
self.generate_argument_declarations(lenv, code)
if self.needs_closure:
code.putln("/* TODO: declare and create scope object */")
code.put_var_declarations(lenv.var_entries)
init = ""
if not self.return_type.is_void:
......@@ -923,6 +926,7 @@ class FuncDefNode(StatNode, BlockNode):
self.put_stararg_decrefs(code)
if acquire_gil:
code.putln("PyGILState_Release(_save);")
code.putln("/* TODO: decref scope object */")
# ----- Return
if not self.return_type.is_void:
code.putln("return %s;" % Naming.retval_cname)
......
......@@ -1386,8 +1386,8 @@ def p_statement(s, ctx, first_statement = 0):
if ctx.api:
error(s.pos, "'api' not allowed with this statement")
elif s.sy == 'def':
if ctx.level not in ('module', 'class', 'c_class', 'property'):
s.error('def statement not allowed here')
# if ctx.level not in ('module', 'class', 'c_class', 'property'):
# s.error('def statement not allowed here')
s.level = ctx.level
return p_def_statement(s)
elif s.sy == 'class':
......
......@@ -47,6 +47,7 @@ class Entry:
# is_self_arg boolean Is the "self" arg of an exttype method
# is_arg boolean Is the arg of a method
# is_local boolean Is a local variable
# in_closure boolean Is referenced in an inner scope
# is_readonly boolean Can't be assigned to
# func_cname string C func implementing Python func
# pos position Source position where declared
......@@ -96,6 +97,7 @@ class Entry:
is_self_arg = 0
is_arg = 0
is_local = 0
in_closure = 0
is_declared_generic = 0
is_readonly = 0
func_cname = None
......@@ -163,6 +165,8 @@ class Scope:
in_cinclude = 0
nogil = 0
temp_prefix = Naming.pyrex_prefix
def __init__(self, name, outer_scope, parent_scope):
# The outer_scope is the next scope in the lookup chain.
# The parent_scope is used to derive the qualified name of this scope.
......@@ -447,7 +451,14 @@ class Scope:
# Look up name in this scope or an enclosing one.
# Return None if not found.
return (self.lookup_here(name)
or (self.outer_scope and self.outer_scope.lookup(name))
or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
or None)
def lookup_from_inner(self, name):
# Look up name in this scope or an enclosing one.
# This is only called from enclosing scopes.
return (self.lookup_here(name)
or (self.outer_scope and self.outer_scope.lookup_from_inner(name))
or None)
def lookup_here(self, name):
......@@ -562,7 +573,7 @@ class Scope:
return entry.cname
n = self.temp_counter
self.temp_counter = n + 1
cname = "%s%d" % (Naming.pyrex_prefix, n)
cname = "%s%d" % (self.temp_prefix, n)
entry = Entry("", cname, type)
entry.used = 1
if type.is_pyobject or type == PyrexTypes.c_py_ssize_t_type:
......@@ -1120,11 +1131,33 @@ class LocalScope(Scope):
entry = self.global_scope().lookup_target(name)
self.entries[name] = entry
def lookup_from_inner(self, name):
entry = self.lookup_here(name)
if entry:
entry.in_closure = 1
return entry
else:
return (self.outer_scope and self.outer_scope.lookup_from_inner(name)) or None
def mangle_closure_cnames(self, scope_var):
for entry in self.entries.values():
if entry.in_closure:
if not hasattr(entry, 'orig_cname'):
entry.orig_cname = entry.cname
entry.cname = scope_var + "->" + entry.cname
class PersistentLocalScope(LocalScope):
def mangle(self, prefix, name):
return "%s->%s" % (scope_obj_cname, name)
class GeneratorLocalScope(LocalScope):
temp_prefix = Naming.cur_scope_cname + "->" + LocalScope.temp_prefix
def mangle_closure_cnames(self, scope_var):
for entry in self.entries.values() + self.temp_entries:
entry.in_closure = 1
LocalScope.mangle_closure_cnames(self, scope_var)
# def mangle(self, prefix, name):
# return "%s->%s" % (Naming.scope_obj_cname, name)
class StructOrUnionScope(Scope):
# Namespace of a C struct or union.
......
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