From 879a240d9184d6f677c6bd3acb307cbafd696678 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Sat, 3 Oct 2009 22:37:01 -0700 Subject: [PATCH] Type inference: assignment marker visitor. --- Cython/Compiler/Main.py | 2 + Cython/Compiler/Nodes.py | 4 ++ Cython/Compiler/Options.py | 1 + Cython/Compiler/Symtab.py | 4 +- Cython/Compiler/TypeInference.py | 69 ++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Cython/Compiler/TypeInference.py diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py index 7f43c94f..162dad27 100644 --- a/Cython/Compiler/Main.py +++ b/Cython/Compiler/Main.py @@ -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, diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 4873ace4..882ca421 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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): diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 97281fb4..13787e24 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -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 diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 39115b71..ba0299f8 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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 index 00000000..9b020259 --- /dev/null +++ b/Cython/Compiler/TypeInference.py @@ -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 -- 2.26.2