]> granicus.if.org Git - python/commitdiff
the previous quick hack to fix def foo((x,y)) failed on some cases
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 17 Feb 2000 22:09:35 +0000 (22:09 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 17 Feb 2000 22:09:35 +0000 (22:09 +0000)
(big surprise).  new solution is a little less hackish.

Code gen adds a TupleArg instance in the argument slot. The tuple arg
includes a copy of the names that it is responsble for binding.  The
PyAssembler uses this information to calculate the correct argcount.

all fix this wacky case: del (a, ((b,), c)), d
which is the same as: del a, b, c, d
(Can't wait for Guido to tell me why.)

solution uses findOp which walks a tree to find out whether it
contains OP_ASSIGN or OP_DELETE or ...

Lib/compiler/pyassem.py
Lib/compiler/pycodegen.py
Tools/compiler/compiler/pyassem.py
Tools/compiler/compiler/pycodegen.py

index 5ae7294a2dad1868a91bf6c470ee43b7673668d9..7efc4ab470e14135f718c5766536a7b10575bfa3 100644 (file)
@@ -42,6 +42,15 @@ CO_NEWLOCALS = 0x0002
 CO_VARARGS = 0x0004
 CO_VARKEYWORDS = 0x0008
 
+class TupleArg:
+    def __init__(self, count, names):
+        self.count = count
+        self.names = names
+    def __repr__(self):
+        return "TupleArg(%s, %s)" % (self.count, self.names)
+    def getName(self):
+        return ".nested%d" % self.count
+
 class PyAssembler:
     """Creates Python code objects
     """
@@ -54,6 +63,7 @@ class PyAssembler:
        self.insts = []
         # used by makeCodeObject
         self._getArgCount(args)
+        print name, args, self.argcount
         self.code = ''
         self.consts = [docstring]
         self.filename = filename
@@ -61,6 +71,10 @@ class PyAssembler:
         self.name = name
         self.names = []
         self.varnames = list(args) or []
+        for i in range(len(self.varnames)):
+            var = self.varnames[i]
+            if isinstance(var, TupleArg):
+                self.varnames[i] = var.getName()
         # lnotab support
         self.firstlineno = 0
         self.lastlineno = 0
@@ -68,14 +82,12 @@ class PyAssembler:
         self.lnotab = ''
 
     def _getArgCount(self, args):
-        if args and args[0][0] == '.':
-            for i in range(len(args)):
-                if args[i][0] == '.':
-                    num = i
-            self.argcount = num + 1
-        else:
-            self.argcount = len(args)
-                
+        self.argcount = len(args)
+        if args:
+            for arg in args:
+                if isinstance(arg, TupleArg):
+                    numNames = len(misc.flatten(arg.names))
+                    self.argcount = self.argcount - numNames 
 
     def __repr__(self):
         return "<bytecode: %d instrs>" % len(self.insts)
@@ -88,7 +100,9 @@ class PyAssembler:
         self.flags = self.flags | CO_OPTIMIZED
 
     def setVarArgs(self):
-        self.flags = self.flags | CO_VARARGS
+        if not self.flags & CO_VARARGS:
+            self.flags = self.flags | CO_VARARGS
+            self.argcount = self.argcount - 1
 
     def setKWArgs(self):
         self.flags = self.flags | CO_VARKEYWORDS
index e9120ccd2828bcfe592bdd51534324e71ae8cf43..4587bf4f3137c428234c5eac65d7fb6b4b5d47a5 100644 (file)
@@ -6,7 +6,7 @@ a generic tool and CodeGenerator as a specific tool.
 """
 
 from p2c import transformer, ast
-from pyassem import StackRef, PyAssembler
+from pyassem import StackRef, PyAssembler, TupleArg
 import dis
 import misc
 import marshal
@@ -203,7 +203,7 @@ class CodeGenerator:
             if type(elt) == types.StringType:
                 args.append(elt)
             elif type(elt) == types.TupleType:
-                args.append(".nested%d" % count)
+                args.append(TupleArg(count, elt))
                 count = count + 1
                 extra.extend(misc.flatten(elt))
             else:
@@ -343,7 +343,6 @@ class CodeGenerator:
 
     def visitLambda(self, node):
         node.name = '<lambda>'
-        node.varargs = node.kwargs = None
         self._visitFuncOrLambda(node, 'Lambda')
         return 1
 
@@ -633,10 +632,13 @@ class CodeGenerator:
         return 1
 
     def visitAssName(self, node):
-        # XXX handle OP_DELETE
-        if node.flags != 'OP_ASSIGN':
+        if node.flags == 'OP_ASSIGN':
+            self.storeName(node.name)
+        elif node.flags == 'OP_DELETE':
+            self.delName(node.name)
+        else:
             print "oops", node.flags
-        self.storeName(node.name)
+        return 1
 
     def visitAssAttr(self, node):
         self.visit(node.expr)
@@ -650,7 +652,8 @@ class CodeGenerator:
         return 1
 
     def visitAssTuple(self, node):
-        self.emit('UNPACK_TUPLE', len(node.nodes))
+        if findOp(node) != 'OP_DELETE':
+            self.emit('UNPACK_TUPLE', len(node.nodes))
         for child in node.nodes:
             self.visit(child)
         return 1
@@ -838,6 +841,7 @@ class CodeGenerator:
         else:
             self.visit(node.globals)
         self.emit('EXEC_STMT')
+        return 1
 
 class LocalNameFinder:
     def __init__(self, names=()):
@@ -882,6 +886,20 @@ class LocalNameFinder:
     def visitAssName(self, node):
         self.names.add(node.name)
 
+class OpFinder:
+    def __init__(self):
+        self.op = None
+    def visitAssName(self, node):
+        if self.op is None:
+            self.op = node.flags
+        elif self.op != node.flags:
+            raise ValueError, "mixed ops in stmt"
+
+def findOp(node):
+    v = OpFinder()
+    walk(node, v)
+    return v.op
+
 class Loop:
     def __init__(self):
         self.startAnchor = StackRef()
index 5ae7294a2dad1868a91bf6c470ee43b7673668d9..7efc4ab470e14135f718c5766536a7b10575bfa3 100644 (file)
@@ -42,6 +42,15 @@ CO_NEWLOCALS = 0x0002
 CO_VARARGS = 0x0004
 CO_VARKEYWORDS = 0x0008
 
+class TupleArg:
+    def __init__(self, count, names):
+        self.count = count
+        self.names = names
+    def __repr__(self):
+        return "TupleArg(%s, %s)" % (self.count, self.names)
+    def getName(self):
+        return ".nested%d" % self.count
+
 class PyAssembler:
     """Creates Python code objects
     """
@@ -54,6 +63,7 @@ class PyAssembler:
        self.insts = []
         # used by makeCodeObject
         self._getArgCount(args)
+        print name, args, self.argcount
         self.code = ''
         self.consts = [docstring]
         self.filename = filename
@@ -61,6 +71,10 @@ class PyAssembler:
         self.name = name
         self.names = []
         self.varnames = list(args) or []
+        for i in range(len(self.varnames)):
+            var = self.varnames[i]
+            if isinstance(var, TupleArg):
+                self.varnames[i] = var.getName()
         # lnotab support
         self.firstlineno = 0
         self.lastlineno = 0
@@ -68,14 +82,12 @@ class PyAssembler:
         self.lnotab = ''
 
     def _getArgCount(self, args):
-        if args and args[0][0] == '.':
-            for i in range(len(args)):
-                if args[i][0] == '.':
-                    num = i
-            self.argcount = num + 1
-        else:
-            self.argcount = len(args)
-                
+        self.argcount = len(args)
+        if args:
+            for arg in args:
+                if isinstance(arg, TupleArg):
+                    numNames = len(misc.flatten(arg.names))
+                    self.argcount = self.argcount - numNames 
 
     def __repr__(self):
         return "<bytecode: %d instrs>" % len(self.insts)
@@ -88,7 +100,9 @@ class PyAssembler:
         self.flags = self.flags | CO_OPTIMIZED
 
     def setVarArgs(self):
-        self.flags = self.flags | CO_VARARGS
+        if not self.flags & CO_VARARGS:
+            self.flags = self.flags | CO_VARARGS
+            self.argcount = self.argcount - 1
 
     def setKWArgs(self):
         self.flags = self.flags | CO_VARKEYWORDS
index e9120ccd2828bcfe592bdd51534324e71ae8cf43..4587bf4f3137c428234c5eac65d7fb6b4b5d47a5 100644 (file)
@@ -6,7 +6,7 @@ a generic tool and CodeGenerator as a specific tool.
 """
 
 from p2c import transformer, ast
-from pyassem import StackRef, PyAssembler
+from pyassem import StackRef, PyAssembler, TupleArg
 import dis
 import misc
 import marshal
@@ -203,7 +203,7 @@ class CodeGenerator:
             if type(elt) == types.StringType:
                 args.append(elt)
             elif type(elt) == types.TupleType:
-                args.append(".nested%d" % count)
+                args.append(TupleArg(count, elt))
                 count = count + 1
                 extra.extend(misc.flatten(elt))
             else:
@@ -343,7 +343,6 @@ class CodeGenerator:
 
     def visitLambda(self, node):
         node.name = '<lambda>'
-        node.varargs = node.kwargs = None
         self._visitFuncOrLambda(node, 'Lambda')
         return 1
 
@@ -633,10 +632,13 @@ class CodeGenerator:
         return 1
 
     def visitAssName(self, node):
-        # XXX handle OP_DELETE
-        if node.flags != 'OP_ASSIGN':
+        if node.flags == 'OP_ASSIGN':
+            self.storeName(node.name)
+        elif node.flags == 'OP_DELETE':
+            self.delName(node.name)
+        else:
             print "oops", node.flags
-        self.storeName(node.name)
+        return 1
 
     def visitAssAttr(self, node):
         self.visit(node.expr)
@@ -650,7 +652,8 @@ class CodeGenerator:
         return 1
 
     def visitAssTuple(self, node):
-        self.emit('UNPACK_TUPLE', len(node.nodes))
+        if findOp(node) != 'OP_DELETE':
+            self.emit('UNPACK_TUPLE', len(node.nodes))
         for child in node.nodes:
             self.visit(child)
         return 1
@@ -838,6 +841,7 @@ class CodeGenerator:
         else:
             self.visit(node.globals)
         self.emit('EXEC_STMT')
+        return 1
 
 class LocalNameFinder:
     def __init__(self, names=()):
@@ -882,6 +886,20 @@ class LocalNameFinder:
     def visitAssName(self, node):
         self.names.add(node.name)
 
+class OpFinder:
+    def __init__(self):
+        self.op = None
+    def visitAssName(self, node):
+        if self.op is None:
+            self.op = node.flags
+        elif self.op != node.flags:
+            raise ValueError, "mixed ops in stmt"
+
+def findOp(node):
+    v = OpFinder()
+    walk(node, v)
+    return v.op
+
 class Loop:
     def __init__(self):
         self.startAnchor = StackRef()