From: Robert Bradshaw Date: Thu, 19 Jun 2008 10:20:20 +0000 (-0700) Subject: Transform nodes for analyse_declarations and analyse_expressions. X-Git-Tag: 0.9.8.1~49^2~121 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b3e446113f1676cf74c1684151dd1c8c62fe9898;p=cython.git Transform nodes for analyse_declarations and analyse_expressions. --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index c61f4a28..fc8464f1 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -972,7 +972,7 @@ class NameNode(AtomicExprNode): if entry.is_builtin: namespace = Naming.builtins_cname else: # entry.is_pyglobal - namespace = entry.namespace_cname + namespace = entry.scope.namespace_cname code.putln( '%s = __Pyx_GetName(%s, %s); %s' % ( self.result_code, @@ -997,7 +997,7 @@ class NameNode(AtomicExprNode): # is_pyglobal seems to be True for module level-globals only. # We use this to access class->tp_dict if necessary. if entry.is_pyglobal: - namespace = self.entry.namespace_cname + namespace = self.entry.scope.namespace_cname if entry.is_member: # if the entry is a member we have to cheat: SetAttr does not work # on types, so we create a descriptor which is then added to tp_dict diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 38026411..47e0a034 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -45,9 +45,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.body.analyse_declarations(env) def process_implementation(self, env, options, result): - self.analyse_declarations(env) + self.scope = env + from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform + AnalyseDeclarationsTransform(env).visit_ModuleNode(self) # self.analyse_declarations(env) env.check_c_classes() - self.body.analyse_expressions(env) + AnalyseExpressionsTransform().visit_ModuleNode(self) # self.body.analyse_expressions(env) env.return_type = PyrexTypes.c_void_type self.referenced_modules = [] self.find_referenced_modules(env, self.referenced_modules, {}) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 3541e67e..faf16dc9 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -802,26 +802,25 @@ class FuncDefNode(StatNode, BlockNode): def need_gil_acquisition(self, lenv): return 0 - - def generate_function_definitions(self, env, code, transforms): - code.mark_pos(self.pos) - # Generate C code for header and body of function - genv = env.global_scope() + + def create_local_scope(self, env): + genv = env + while env.is_py_class_scope or env.is_c_class_scope: + env = env.outer_scope lenv = LocalScope(name = self.entry.name, outer_scope = genv) lenv.return_type = self.return_type type = self.entry.type if type.is_cfunction: lenv.nogil = type.nogil and not type.with_gil + self.local_scope = lenv + return lenv + + def generate_function_definitions(self, env, code, transforms): + # Generate C code for header and body of function code.init_labels() - self.declare_arguments(lenv) - transforms.run('before_analyse_function', self, env=env, lenv=lenv, genv=genv) - self.body.analyse_control_flow(lenv) - self.body.analyse_declarations(lenv) - self.body.analyse_expressions(lenv) - transforms.run('after_analyse_function', self, env=env, lenv=lenv, genv=genv) - # Code for nested function definitions would go here - # if we supported them, which we probably won't. + lenv = self.local_scope # ----- Top-level constants used by this function + code.mark_pos(self.pos) self.generate_interned_num_decls(lenv, code) self.generate_interned_string_decls(lenv, code) self.generate_py_string_decls(lenv, code) @@ -975,8 +974,9 @@ class CFuncDefNode(FuncDefNode): # # with_gil boolean Acquire GIL around body # type CFuncType + # py_func wrapper for calling from Python - child_attrs = ["base_type", "declarator", "body"] + child_attrs = ["base_type", "declarator", "body", "py_func"] def unqualified_name(self): return self.entry.name @@ -1838,6 +1838,8 @@ class OverrideCheckNode(StatNode): # body child_attrs = ['body'] + + body = None def analyse_expressions(self, env): self.args = env.arg_entries @@ -1915,19 +1917,27 @@ class PyClassDefNode(StatNode, BlockNode): self.classobj = ExprNodes.ClassNode(pos, name = name, bases = bases, dict = self.dict, doc = doc_node) self.target = ExprNodes.NameNode(pos, name = name) + + def create_scope(self, env): + genv = env + while env.is_py_class_scope or env.is_c_class_scope: + env = env.outer_scope + cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv) + return cenv def analyse_declarations(self, env): self.target.analyse_target_declaration(env) + cenv = self.create_scope(env) + cenv.class_obj_cname = self.target.entry.cname + self.body.analyse_declarations(cenv) def analyse_expressions(self, env): self.dict.analyse_expressions(env) self.classobj.analyse_expressions(env) genv = env.global_scope() - cenv = PyClassScope(name = self.name, outer_scope = genv) + cenv = self.scope cenv.class_dict_cname = self.dict.result_code - cenv.class_obj_cname = self.classobj.result_code - self.scope = cenv - self.body.analyse_declarations(cenv) + cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result_code self.body.analyse_expressions(cenv) self.target.analyse_target_expression(env, self.classobj) self.dict.release_temp(env) diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 598b19cb..ef4d9b83 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -117,7 +117,7 @@ class WithTransform(VisitorTransform): def visit_Node(self, node): self.visitchildren(node) - return node + return node def visit_WithStatNode(self, node): excinfo_name = temp_name_handle('EXCINFO') @@ -142,3 +142,46 @@ class WithTransform(VisitorTransform): result.stats[4].body.stats[0].except_clauses[0].excinfo_target = excinfo_target return result.stats + +class AnalyseDeclarationsTransform(VisitorTransform): + + def __init__(self, env): + VisitorTransform.__init__(self) + self.env_stack = [env] + + def visit_ModuleNode(self, node): + node.analyse_declarations(self.env_stack[-1]) + self.visitchildren(node) + return node + + def visit_FuncDefNode(self, node): + lenv = node.create_local_scope(self.env_stack[-1]) + node.body.analyse_control_flow(lenv) # this will be totally refactored + node.declare_arguments(lenv) + node.body.analyse_declarations(lenv) + self.env_stack.append(lenv) + self.visitchildren(node) + self.env_stack.pop() + return node + + def visit_Node(self, node): + self.visitchildren(node) + return node + + +class AnalyseExpressionsTransform(VisitorTransform): + + def visit_ModuleNode(self, node): + node.body.analyse_expressions(node.scope) + self.visitchildren(node) + return node + + def visit_FuncDefNode(self, node): + node.body.analyse_expressions(node.local_scope) + self.visitchildren(node) + return node + + def visit_Node(self, node): + self.visitchildren(node) + return node + diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 529deade..b98bdc3f 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -608,6 +608,9 @@ class Scope: return 0 class PreImportScope(Scope): + + namespace_cname = Naming.preimport_cname + def __init__(self): Scope.__init__(self, Options.pre_import, None, None) @@ -615,7 +618,6 @@ class PreImportScope(Scope): entry = self.declare(name, name, py_object_type, pos) entry.is_variable = True entry.is_pyglobal = True - entry.namespace_cname = Naming.preimport_cname return entry @@ -761,6 +763,7 @@ class ModuleScope(Scope): self.has_extern_class = 0 self.cached_builtins = [] self.undeclared_cached_builtins = [] + self.namespace_cname = self.module_cname def qualifying_scope(self): return self.parent_module @@ -876,7 +879,6 @@ class ModuleScope(Scope): raise InternalError( "Non-cdef global variable is not a generic Python object") entry.is_pyglobal = 1 - entry.namespace_cname = self.module_cname else: entry.is_cglobal = 1 self.var_entries.append(entry) @@ -1197,7 +1199,6 @@ class PyClassScope(ClassScope): entry = Scope.declare_var(self, name, type, pos, cname, visibility, is_cdef) entry.is_pyglobal = 1 - entry.namespace_cname = self.class_obj_cname return entry def allocate_temp(self, type): @@ -1294,7 +1295,7 @@ class CClassScope(ClassScope): entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that # I keep it in for now. is_member should be enough # later on - entry.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname + self.namespace_cname = "(PyObject *)%s" % self.parent_type.typeptr_cname entry.interned_cname = self.intern_identifier(name) return entry diff --git a/Cython/Compiler/TreeFragment.py b/Cython/Compiler/TreeFragment.py index 0eff1b82..b6e261e4 100644 --- a/Cython/Compiler/TreeFragment.py +++ b/Cython/Compiler/TreeFragment.py @@ -158,7 +158,7 @@ INDENT_RE = re.compile(ur"^ *") def strip_common_indent(lines): "Strips empty lines and common indentation from the list of strings given in lines" lines = [x for x in lines if x.strip() != u""] - minindent = min(len(INDENT_RE.match(x).group(0)) for x in lines) + minindent = min([len(INDENT_RE.match(x).group(0)) for x in lines]) lines = [x[minindent:] for x in lines] return lines