[pypy-svn] r66552 - pypy/branch/parser-compiler/pypy/interpreter/astcompiler
benjamin at codespeak.net
benjamin at codespeak.net
Thu Jul 23 19:45:40 CEST 2009
Author: benjamin
Date: Thu Jul 23 19:45:39 2009
New Revision: 66552
Modified:
pypy/branch/parser-compiler/pypy/interpreter/astcompiler/codegen.py
Log:
optimize unpacking in assignment
Modified: pypy/branch/parser-compiler/pypy/interpreter/astcompiler/codegen.py
==============================================================================
--- pypy/branch/parser-compiler/pypy/interpreter/astcompiler/codegen.py (original)
+++ pypy/branch/parser-compiler/pypy/interpreter/astcompiler/codegen.py Thu Jul 23 19:45:39 2009
@@ -8,6 +8,7 @@
from pypy.interpreter.pyparser.error import SyntaxError
from pypy.tool import stdlib_opcode as ops
from pypy.interpreter.pyparser import future
+from pypy.interpreter.error import OperationError
from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX
@@ -619,6 +620,8 @@
def visit_Assign(self, assign):
self.update_position(assign.lineno, True)
+ if self._optimize_unpacking(assign):
+ return
assign.value.walkabout(self)
duplications = len(assign.targets) - 1
for i in range(len(assign.targets)):
@@ -626,6 +629,62 @@
self.emit_op(ops.DUP_TOP)
assign.targets[i].walkabout(self)
+ def _optimize_unpacking(self, assign):
+ if len(assign.targets) != 1:
+ return False
+ targets = self._list_from_sequence_node(assign.targets[0], False)
+ if targets is None:
+ return False
+ values = self._list_from_sequence_node(assign.value, True)
+ if values is None:
+ return False
+ targets_count = len(targets)
+ values_count = len(values)
+ if targets_count != values_count:
+ return False
+ for target in targets:
+ if not isinstance(target, ast.Name):
+ break
+ else:
+ self.visit_sequence(values)
+ seen_names = {}
+ for i in range(targets_count - 1, -1, -1):
+ target = targets[i]
+ assert isinstance(target, ast.Name)
+ if target.id not in seen_names:
+ seen_names[target.id] = True
+ self.name_op(target.id, ast.Store)
+ else:
+ self.emit_op(ops.POP_TOP)
+ return True
+ if values_count > 3:
+ return False
+ self.visit_sequence(values)
+ if values_count == 2:
+ self.emit_op(ops.ROT_TWO)
+ elif values_count == 3:
+ self.emit_op(ops.ROT_THREE)
+ self.emit_op(ops.ROT_TWO)
+ self.visit_sequence(targets)
+ return True
+
+ def _list_from_sequence_node(self, node, const_possible):
+ if isinstance(node, ast.Tuple):
+ nodes = node.elts
+ elif isinstance(node, ast.List):
+ nodes = node.elts
+ elif const_possible and isinstance(node, ast.Const):
+ try:
+ values_w = self.space.unpackiterable(node.value)
+ except OperationError:
+ return None
+ line = node.lineno
+ column = node.col_offset
+ nodes = [ast.Const(obj, line, column) for obj in values_w]
+ else:
+ nodes = None
+ return nodes
+
def visit_With(self, wih):
self.update_position(wih.lineno, True)
body_block = self.new_block()
More information about the Pypy-commit
mailing list