From af6263020b4f0e7efb30ac66f6c8992b0a308fe9 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Thu, 19 Jun 2008 16:52:46 -0700 Subject: [PATCH] Add indirection to closure variables --- Cython/Compiler/Code.py | 2 ++ Cython/Compiler/Naming.py | 3 ++- Cython/Compiler/Nodes.py | 8 +++++-- Cython/Compiler/Parsing.py | 4 ++-- Cython/Compiler/Symtab.py | 43 +++++++++++++++++++++++++++++++++----- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index d27ae4f9..afba02f8 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -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" ### diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index 926b336c..4296bf71 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -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__" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 3e1291de..6a791efe 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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) diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 4d5de6cf..f7c9ca8c 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -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': diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 77a49cc1..1c016200 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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): +class GeneratorLocalScope(LocalScope): + + temp_prefix = Naming.cur_scope_cname + "->" + LocalScope.temp_prefix - def mangle(self, prefix, name): - return "%s->%s" % (scope_obj_cname, name) + 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. -- 2.26.2