Transform nodes for analyse_declarations and analyse_expressions.
authorRobert Bradshaw <robertwb@math.washington.edu>
Thu, 19 Jun 2008 10:20:20 +0000 (03:20 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Thu, 19 Jun 2008 10:20:20 +0000 (03:20 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Symtab.py
Cython/Compiler/TreeFragment.py

index c61f4a28b165538dc3f825fc2bf4e8730a340f38..fc8464f167f15e0fce7211cd33c97290b4b2f68d 100644 (file)
@@ -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
index 3802641137d502931bf0795d11104cf9308a8e8d..47e0a034e7b30b8bc5edb332243f06569fe3bb3d 100644 (file)
@@ -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, {})
index 3541e67e56e314cfe4ffdb07f0120c4d71056504..faf16dc96dbd447751277284fe8e883165b35944 100644 (file)
@@ -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)
index 598b19cb7d9aedbc7375a2e89fdea5f39a5b05f5..ef4d9b8328ac6420bbaa1896f5ba88c10273b538 100644 (file)
@@ -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
+
index 529deadeb0b1d8ffb44a703389af5855f467eca8..b98bdc3f5df8eee0e461f17e3d1826b0389bfdd3 100644 (file)
@@ -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
 
index 0eff1b82fbe1e88040169060eeb05582b8a08ce7..b6e261e46c53b658c68dca3f8b849b2a2cb9cb17 100644 (file)
@@ -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