Type inference: assignment marker visitor.
authorRobert Bradshaw <robertwb@math.washington.edu>
Sun, 4 Oct 2009 05:37:01 +0000 (22:37 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Sun, 4 Oct 2009 05:37:01 +0000 (22:37 -0700)
Cython/Compiler/Main.py
Cython/Compiler/Nodes.py
Cython/Compiler/Options.py
Cython/Compiler/Symtab.py
Cython/Compiler/TypeInference.py [new file with mode: 0644]

index 7f43c94f88b3829089d51b9b5800fb78b557d6cc..162dad270cd2291e1a9afd7035074b7e08671ec7 100644 (file)
@@ -87,6 +87,7 @@ class Context(object):
         from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
         from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
         from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
+        from TypeInference import MarkAssignments
         from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck
         from AnalysedTreeTransforms import AutoTestDictTransform
         from AutoDocTransforms import EmbedSignature
@@ -129,6 +130,7 @@ class Context(object):
             AnalyseDeclarationsTransform(self),
             AutoTestDictTransform(self),
             EmbedSignature(self),
+            MarkAssignments(self),
             TransformBuiltinMethods(self),
             IntroduceBufferAuxiliaryVars(self),
             _check_c_declarations,
index 4873ace4d862373ef1356f0da1812279985194bb..882ca421851bdeed53e176cf8a8f1fe29b75a00c 100644 (file)
@@ -3197,6 +3197,10 @@ class InPlaceAssignmentNode(AssignmentNode):
         self.lhs.annotate(code)
         self.rhs.annotate(code)
         self.dup.annotate(code)
+    
+    def create_binop_node(self):
+        import ExprNodes
+        return ExprNodes.binop_node(self.pos, self.op, self.lhs, self.rhs)
 
 
 class PrintStatNode(StatNode):
index 97281fb406f452dbf09e2e17f0e75f19b90a5de1..13787e241ffe5f1b28c9f210ddff2ce7ed10b48d 100644 (file)
@@ -68,6 +68,7 @@ option_defaults = {
     'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this...
     'callspec' : "",
     'profile': False,
+    'infer_types': True,
     'autotestdict': True,
 
 # test support
index 39115b71d6d846b943e539820cdcc995da6b3690..ba0299f8040a1d794ed33826ceb7689977cd604b 100644 (file)
@@ -114,9 +114,10 @@ class Entry(object):
     # api              boolean    Generate C API for C class or function
     # utility_code     string     Utility code needed when this entry is used
     #
-    # buffer_aux      BufferAux or None  Extra information needed for buffer variables
+    # buffer_aux       BufferAux or None  Extra information needed for buffer variables
     # inline_func_in_pxd boolean  Hacky special case for inline function in pxd file.
     #                             Ideally this should not be necesarry.
+    # assignments      [ExprNode] List of expressions that get assigned to this entry.
 
     inline_func_in_pxd = False
     borrowed = 0
@@ -171,6 +172,7 @@ class Entry(object):
         self.type = type
         self.pos = pos
         self.init = init
+        self.assignments = []
         
     def redeclared(self, pos):
         error(pos, "'%s' does not match previous declaration" % self.name)
diff --git a/Cython/Compiler/TypeInference.py b/Cython/Compiler/TypeInference.py
new file mode 100644 (file)
index 0000000..9b02025
--- /dev/null
@@ -0,0 +1,69 @@
+import ExprNodes
+import PyrexTypes
+from Visitor import CythonTransform
+
+class TypedExprNode(ExprNodes.ExprNode):
+    # Used for declaring assignments of a specified type whithout a known entry.
+    def __init__(self, type):
+        self.type = type
+
+object_expr = TypedExprNode(PyrexTypes.py_object_type)
+
+class MarkAssignments(CythonTransform):
+    
+    def mark_assignment(self, lhs, rhs):
+        print lhs.pos[1:]
+        if isinstance(lhs, ExprNodes.NameNode):
+            lhs.entry.assignments.append(rhs)
+            print lhs.name, rhs
+        elif isinstance(lhs, ExprNodes.SequenceNode):
+            for arg in lhs.args:
+                self.mark_assignment(arg, object_expr)
+        else:
+            # Could use this info to infer cdef class attributes...
+            pass
+    
+    def visit_SingleAssignmentNode(self, node):
+        self.mark_assignment(node.lhs, node.rhs)
+        self.visitchildren(node)
+        return node
+
+    def visit_CascadedAssignmentNode(self, node):
+        for lhs in node.lhs_list:
+            self.mark_assignment(lhs, node.rhs)
+        self.visitchildren(node)
+        return node
+    
+    def visit_InPlaceAssignmentNode(self, node):
+        self.mark_assignment(node.lhs, node.create_binop_node())
+        self.visitchildren(node)
+        return node
+
+    def visit_ForInStatNode(self, node):
+        # TODO: Figure out how this interacts with the range optimization...
+        self.mark_assignment(node.target, object_expr)
+        self.visitchildren(node)
+        return node
+
+    def visit_ForFromStatNode(self, node):
+        self.mark_assignment(node.target, node.bound1)
+        if node.step is not None:
+            self.mark_assignment(node.target, ExprNodes.binop_node(self.pos, '+', node.bound1, node.step))
+        self.visitchildren(node)
+        return node
+
+    def visit_ExceptClauseNode(self, node):
+        if node.target is not None:
+            self.mark_assignment(node.target, object_expr)
+        self.visitchildren(node)
+        return node
+    
+    def visit_FromCImportStatNode(self, node):
+        raise NotImplementedError # Can't occur in local scopes anyways...
+
+    def visit_FromImportStatNode(self, node):
+        for name, target in node.items:
+            if name != "*":
+                self.mark_assignment(target, object_expr)
+        self.visitchildren(node)
+        return node