Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3ec7e2c

Browse files
committed
the previous quick hack to fix def foo((x,y)) failed on some cases
(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 ...
1 parent 7708d69 commit 3ec7e2c

4 files changed

Lines changed: 96 additions & 32 deletions

File tree

Lib/compiler/pyassem.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
CO_VARARGS = 0x0004
4343
CO_VARKEYWORDS = 0x0008
4444

45+
class TupleArg:
46+
def __init__(self, count, names):
47+
self.count = count
48+
self.names = names
49+
def __repr__(self):
50+
return "TupleArg(%s, %s)" % (self.count, self.names)
51+
def getName(self):
52+
return ".nested%d" % self.count
53+
4554
class PyAssembler:
4655
"""Creates Python code objects
4756
"""
@@ -54,28 +63,31 @@ def __init__(self, args=(), name='?', filename='<?>',
5463
self.insts = []
5564
# used by makeCodeObject
5665
self._getArgCount(args)
66+
print name, args, self.argcount
5767
self.code = ''
5868
self.consts = [docstring]
5969
self.filename = filename
6070
self.flags = CO_NEWLOCALS
6171
self.name = name
6272
self.names = []
6373
self.varnames = list(args) or []
74+
for i in range(len(self.varnames)):
75+
var = self.varnames[i]
76+
if isinstance(var, TupleArg):
77+
self.varnames[i] = var.getName()
6478
# lnotab support
6579
self.firstlineno = 0
6680
self.lastlineno = 0
6781
self.last_addr = 0
6882
self.lnotab = ''
6983

7084
def _getArgCount(self, args):
71-
if args and args[0][0] == '.':
72-
for i in range(len(args)):
73-
if args[i][0] == '.':
74-
num = i
75-
self.argcount = num + 1
76-
else:
77-
self.argcount = len(args)
78-
85+
self.argcount = len(args)
86+
if args:
87+
for arg in args:
88+
if isinstance(arg, TupleArg):
89+
numNames = len(misc.flatten(arg.names))
90+
self.argcount = self.argcount - numNames
7991

8092
def __repr__(self):
8193
return "<bytecode: %d instrs>" % len(self.insts)
@@ -88,7 +100,9 @@ def setOptimized(self):
88100
self.flags = self.flags | CO_OPTIMIZED
89101

90102
def setVarArgs(self):
91-
self.flags = self.flags | CO_VARARGS
103+
if not self.flags & CO_VARARGS:
104+
self.flags = self.flags | CO_VARARGS
105+
self.argcount = self.argcount - 1
92106

93107
def setKWArgs(self):
94108
self.flags = self.flags | CO_VARKEYWORDS

Lib/compiler/pycodegen.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"""
77

88
from p2c import transformer, ast
9-
from pyassem import StackRef, PyAssembler
9+
from pyassem import StackRef, PyAssembler, TupleArg
1010
import dis
1111
import misc
1212
import marshal
@@ -203,7 +203,7 @@ def generateArglist(self, arglist):
203203
if type(elt) == types.StringType:
204204
args.append(elt)
205205
elif type(elt) == types.TupleType:
206-
args.append(".nested%d" % count)
206+
args.append(TupleArg(count, elt))
207207
count = count + 1
208208
extra.extend(misc.flatten(elt))
209209
else:
@@ -343,7 +343,6 @@ def visitFunction(self, node):
343343

344344
def visitLambda(self, node):
345345
node.name = '<lambda>'
346-
node.varargs = node.kwargs = None
347346
self._visitFuncOrLambda(node, 'Lambda')
348347
return 1
349348

@@ -633,10 +632,13 @@ def visitAssign(self, node):
633632
return 1
634633

635634
def visitAssName(self, node):
636-
# XXX handle OP_DELETE
637-
if node.flags != 'OP_ASSIGN':
635+
if node.flags == 'OP_ASSIGN':
636+
self.storeName(node.name)
637+
elif node.flags == 'OP_DELETE':
638+
self.delName(node.name)
639+
else:
638640
print "oops", node.flags
639-
self.storeName(node.name)
641+
return 1
640642

641643
def visitAssAttr(self, node):
642644
self.visit(node.expr)
@@ -650,7 +652,8 @@ def visitAssAttr(self, node):
650652
return 1
651653

652654
def visitAssTuple(self, node):
653-
self.emit('UNPACK_TUPLE', len(node.nodes))
655+
if findOp(node) != 'OP_DELETE':
656+
self.emit('UNPACK_TUPLE', len(node.nodes))
654657
for child in node.nodes:
655658
self.visit(child)
656659
return 1
@@ -838,6 +841,7 @@ def visitExec(self, node):
838841
else:
839842
self.visit(node.globals)
840843
self.emit('EXEC_STMT')
844+
return 1
841845

842846
class LocalNameFinder:
843847
def __init__(self, names=()):
@@ -882,6 +886,20 @@ def visitClassdef(self, node):
882886
def visitAssName(self, node):
883887
self.names.add(node.name)
884888

889+
class OpFinder:
890+
def __init__(self):
891+
self.op = None
892+
def visitAssName(self, node):
893+
if self.op is None:
894+
self.op = node.flags
895+
elif self.op != node.flags:
896+
raise ValueError, "mixed ops in stmt"
897+
898+
def findOp(node):
899+
v = OpFinder()
900+
walk(node, v)
901+
return v.op
902+
885903
class Loop:
886904
def __init__(self):
887905
self.startAnchor = StackRef()

Tools/compiler/compiler/pyassem.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
CO_VARARGS = 0x0004
4343
CO_VARKEYWORDS = 0x0008
4444

45+
class TupleArg:
46+
def __init__(self, count, names):
47+
self.count = count
48+
self.names = names
49+
def __repr__(self):
50+
return "TupleArg(%s, %s)" % (self.count, self.names)
51+
def getName(self):
52+
return ".nested%d" % self.count
53+
4554
class PyAssembler:
4655
"""Creates Python code objects
4756
"""
@@ -54,28 +63,31 @@ def __init__(self, args=(), name='?', filename='<?>',
5463
self.insts = []
5564
# used by makeCodeObject
5665
self._getArgCount(args)
66+
print name, args, self.argcount
5767
self.code = ''
5868
self.consts = [docstring]
5969
self.filename = filename
6070
self.flags = CO_NEWLOCALS
6171
self.name = name
6272
self.names = []
6373
self.varnames = list(args) or []
74+
for i in range(len(self.varnames)):
75+
var = self.varnames[i]
76+
if isinstance(var, TupleArg):
77+
self.varnames[i] = var.getName()
6478
# lnotab support
6579
self.firstlineno = 0
6680
self.lastlineno = 0
6781
self.last_addr = 0
6882
self.lnotab = ''
6983

7084
def _getArgCount(self, args):
71-
if args and args[0][0] == '.':
72-
for i in range(len(args)):
73-
if args[i][0] == '.':
74-
num = i
75-
self.argcount = num + 1
76-
else:
77-
self.argcount = len(args)
78-
85+
self.argcount = len(args)
86+
if args:
87+
for arg in args:
88+
if isinstance(arg, TupleArg):
89+
numNames = len(misc.flatten(arg.names))
90+
self.argcount = self.argcount - numNames
7991

8092
def __repr__(self):
8193
return "<bytecode: %d instrs>" % len(self.insts)
@@ -88,7 +100,9 @@ def setOptimized(self):
88100
self.flags = self.flags | CO_OPTIMIZED
89101

90102
def setVarArgs(self):
91-
self.flags = self.flags | CO_VARARGS
103+
if not self.flags & CO_VARARGS:
104+
self.flags = self.flags | CO_VARARGS
105+
self.argcount = self.argcount - 1
92106

93107
def setKWArgs(self):
94108
self.flags = self.flags | CO_VARKEYWORDS

Tools/compiler/compiler/pycodegen.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"""
77

88
from p2c import transformer, ast
9-
from pyassem import StackRef, PyAssembler
9+
from pyassem import StackRef, PyAssembler, TupleArg
1010
import dis
1111
import misc
1212
import marshal
@@ -203,7 +203,7 @@ def generateArglist(self, arglist):
203203
if type(elt) == types.StringType:
204204
args.append(elt)
205205
elif type(elt) == types.TupleType:
206-
args.append(".nested%d" % count)
206+
args.append(TupleArg(count, elt))
207207
count = count + 1
208208
extra.extend(misc.flatten(elt))
209209
else:
@@ -343,7 +343,6 @@ def visitFunction(self, node):
343343

344344
def visitLambda(self, node):
345345
node.name = '<lambda>'
346-
node.varargs = node.kwargs = None
347346
self._visitFuncOrLambda(node, 'Lambda')
348347
return 1
349348

@@ -633,10 +632,13 @@ def visitAssign(self, node):
633632
return 1
634633

635634
def visitAssName(self, node):
636-
# XXX handle OP_DELETE
637-
if node.flags != 'OP_ASSIGN':
635+
if node.flags == 'OP_ASSIGN':
636+
self.storeName(node.name)
637+
elif node.flags == 'OP_DELETE':
638+
self.delName(node.name)
639+
else:
638640
print "oops", node.flags
639-
self.storeName(node.name)
641+
return 1
640642

641643
def visitAssAttr(self, node):
642644
self.visit(node.expr)
@@ -650,7 +652,8 @@ def visitAssAttr(self, node):
650652
return 1
651653

652654
def visitAssTuple(self, node):
653-
self.emit('UNPACK_TUPLE', len(node.nodes))
655+
if findOp(node) != 'OP_DELETE':
656+
self.emit('UNPACK_TUPLE', len(node.nodes))
654657
for child in node.nodes:
655658
self.visit(child)
656659
return 1
@@ -838,6 +841,7 @@ def visitExec(self, node):
838841
else:
839842
self.visit(node.globals)
840843
self.emit('EXEC_STMT')
844+
return 1
841845

842846
class LocalNameFinder:
843847
def __init__(self, names=()):
@@ -882,6 +886,20 @@ def visitClassdef(self, node):
882886
def visitAssName(self, node):
883887
self.names.add(node.name)
884888

889+
class OpFinder:
890+
def __init__(self):
891+
self.op = None
892+
def visitAssName(self, node):
893+
if self.op is None:
894+
self.op = node.flags
895+
elif self.op != node.flags:
896+
raise ValueError, "mixed ops in stmt"
897+
898+
def findOp(node):
899+
v = OpFinder()
900+
walk(node, v)
901+
return v.op
902+
885903
class Loop:
886904
def __init__(self):
887905
self.startAnchor = StackRef()

0 commit comments

Comments
 (0)