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

Skip to content

Commit be317e6

Browse files
committed
patches from Mark Hammond
Attached is a set of diffs for the .py compiler that adds support for the new extended call syntax. compiler/ast.py: CallFunc node gets 2 new children to support extended call syntax - "star_args" (for "*args") and "dstar_args" (for "**args") compiler/pyassem.py It appear that self.lnotab is supposed to be responsible for tracking line numbers, but self.firstlineno was still hanging around. Removed self.firstlineno completely. NOTE - I didnt actually test that the generated code has the correct line numbers!! Stack depth tracking appeared a little broken - the checks never made it beyond the "self.patterns" check - thus, the custom methods were never called! Fixed this. (XXX Jeremy notes: I think this code is still broken because it doesn't track stack effects across block bounaries.) Added support for the new extended call syntax opcodes for depth calculations. compiler/pycodegen.py Added support for the new extended call syntax opcodes. compiler/transformer.py Added support for the new extended call syntax.
1 parent 0a4f1ff commit be317e6

8 files changed

Lines changed: 116 additions & 28 deletions

File tree

Lib/compiler/ast.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,15 @@ def __repr__(self):
445445
class CallFunc(Node):
446446
nodes['call_func'] = 'CallFunc'
447447

448-
def __init__(self, node, args):
448+
def __init__(self, node, args, star_args = None, dstar_args = None):
449449
self.node = node
450450
self.args = args
451-
self._children = ('call_func', node, args)
451+
self.star_args = star_args
452+
self.dstar_args = dstar_args
453+
self._children = ('call_func', node, args, star_args, dstar_args)
452454

453455
def __repr__(self):
454-
return "CallFunc(%s,%s)" % self._children[1:]
456+
return "CallFunc(%s,%s,*%s, **%s)" % self._children[1:]
455457

456458
class Keyword(Node):
457459
nodes['keyword'] = 'Keyword'

Lib/compiler/pyassem.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ def __init__(self, name, filename, args=(), optimized=0):
149149
self.flags = CO_OPTIMIZED | CO_NEWLOCALS
150150
else:
151151
self.flags = 0
152-
self.firstlineno = None
153152
self.consts = []
154153
self.names = []
155154
self.varnames = list(args) or []
@@ -314,8 +313,6 @@ def makeByteCode(self):
314313
oparg = t[1]
315314
if opname == "SET_LINENO":
316315
lnotab.nextLine(oparg)
317-
if self.firstlineno is None:
318-
self.firstlineno = oparg
319316
hi, lo = twobyte(oparg)
320317
try:
321318
lnotab.addCode(self.opnum[opname], lo, hi)
@@ -342,7 +339,7 @@ def newCodeObject(self):
342339
return new.code(argcount, nlocals, self.stacksize, self.flags,
343340
self.lnotab.getCode(), self.getConsts(),
344341
tuple(self.names), tuple(self.varnames),
345-
self.filename, self.name, self.firstlineno,
342+
self.filename, self.name, self.lnotab.firstline,
346343
self.lnotab.getTable())
347344

348345
def getConsts(self):
@@ -464,14 +461,16 @@ def findDepth(self, insts):
464461
if depth > maxDepth:
465462
maxDepth = depth
466463
# now check patterns
467-
for pat, delta in self.patterns:
464+
for pat, pat_delta in self.patterns:
468465
if opname[:len(pat)] == pat:
466+
delta = pat_delta
469467
depth = depth + delta
470468
break
471469
# if we still haven't found a match
472470
if delta == 0:
473-
meth = getattr(self, opname)
474-
depth = depth + meth(i[1])
471+
meth = getattr(self, opname, None)
472+
if meth is not None:
473+
depth = depth + meth(i[1])
475474
if depth < 0:
476475
depth = 0
477476
return maxDepth
@@ -527,6 +526,12 @@ def BUILD_LIST(self, count):
527526
def CALL_FUNCTION(self, argc):
528527
hi, lo = divmod(argc, 256)
529528
return lo + hi * 2
529+
def CALL_FUNCTION_VAR(self, argc):
530+
return self.CALL_FUNCTION(argc)+1
531+
def CALL_FUNCTION_KW(self, argc):
532+
return self.CALL_FUNCTION(argc)+1
533+
def CALL_FUNCTION_VAR_KW(self, argc):
534+
return self.CALL_FUNCTION(argc)+2
530535
def MAKE_FUNCTION(self, argc):
531536
return -argc
532537
def BUILD_SLICE(self, argc):

Lib/compiler/pycodegen.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
from compiler import pyassem, misc
1010
from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
1111

12+
callfunc_opcode_info = {
13+
# (Have *args, Have **args) : opcode
14+
(0,0) : "CALL_FUNCTION",
15+
(1,0) : "CALL_FUNCTION_VAR",
16+
(0,1) : "CALL_FUNCTION_KW",
17+
(1,1) : "CALL_FUNCTION_VAR_KW",
18+
}
19+
1220
def compile(filename):
1321
f = open(filename)
1422
buf = f.read()
@@ -478,7 +486,14 @@ def visitCallFunc(self, node):
478486
kw = kw + 1
479487
else:
480488
pos = pos + 1
481-
self.emit('CALL_FUNCTION', kw << 8 | pos)
489+
if node.star_args is not None:
490+
self.visit(node.star_args)
491+
if node.dstar_args is not None:
492+
self.visit(node.dstar_args)
493+
have_star = node.star_args is not None
494+
have_dstar = node.dstar_args is not None
495+
opcode = callfunc_opcode_info[have_star, have_dstar]
496+
self.emit(opcode, kw << 8 | pos)
482497

483498
def visitPrint(self, node):
484499
self.emit('SET_LINENO', node.lineno)

Lib/compiler/transformer.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,10 +984,32 @@ def com_call_function(self, primaryNode, nodelist):
984984
return Node('call_func', primaryNode, [ ])
985985
args = [ ]
986986
kw = 0
987-
for i in range(1, len(nodelist), 2):
988-
kw, result = self.com_argument(nodelist[i], kw)
987+
len_nodelist = len(nodelist)
988+
for i in range(1, len_nodelist, 2):
989+
node = nodelist[i]
990+
if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
991+
break
992+
kw, result = self.com_argument(node, kw)
989993
args.append(result)
990-
return Node('call_func', primaryNode, args)
994+
else:
995+
i = i + 1 # No broken by star arg, so skip the last one we processed.
996+
star_node = dstar_node = None
997+
while i < len_nodelist:
998+
tok = nodelist[i]
999+
ch = nodelist[i+1]
1000+
i = i + 3
1001+
if tok[0]==token.STAR:
1002+
if star_node is not None:
1003+
raise SyntaxError, 'already have the varargs indentifier'
1004+
star_node = self.com_node(ch)
1005+
elif tok[0]==token.DOUBLESTAR:
1006+
if dstar_node is not None:
1007+
raise SyntaxError, 'already have the kwargs indentifier'
1008+
dstar_node = self.com_node(ch)
1009+
else:
1010+
raise SyntaxError, 'unknown node type: %s' % tok
1011+
1012+
return Node('call_func', primaryNode, args, star_node, dstar_node)
9911013

9921014
def com_argument(self, nodelist, kw):
9931015
if len(nodelist) == 2:

Tools/compiler/compiler/ast.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,15 @@ def __repr__(self):
445445
class CallFunc(Node):
446446
nodes['call_func'] = 'CallFunc'
447447

448-
def __init__(self, node, args):
448+
def __init__(self, node, args, star_args = None, dstar_args = None):
449449
self.node = node
450450
self.args = args
451-
self._children = ('call_func', node, args)
451+
self.star_args = star_args
452+
self.dstar_args = dstar_args
453+
self._children = ('call_func', node, args, star_args, dstar_args)
452454

453455
def __repr__(self):
454-
return "CallFunc(%s,%s)" % self._children[1:]
456+
return "CallFunc(%s,%s,*%s, **%s)" % self._children[1:]
455457

456458
class Keyword(Node):
457459
nodes['keyword'] = 'Keyword'

Tools/compiler/compiler/pyassem.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ def __init__(self, name, filename, args=(), optimized=0):
149149
self.flags = CO_OPTIMIZED | CO_NEWLOCALS
150150
else:
151151
self.flags = 0
152-
self.firstlineno = None
153152
self.consts = []
154153
self.names = []
155154
self.varnames = list(args) or []
@@ -314,8 +313,6 @@ def makeByteCode(self):
314313
oparg = t[1]
315314
if opname == "SET_LINENO":
316315
lnotab.nextLine(oparg)
317-
if self.firstlineno is None:
318-
self.firstlineno = oparg
319316
hi, lo = twobyte(oparg)
320317
try:
321318
lnotab.addCode(self.opnum[opname], lo, hi)
@@ -342,7 +339,7 @@ def newCodeObject(self):
342339
return new.code(argcount, nlocals, self.stacksize, self.flags,
343340
self.lnotab.getCode(), self.getConsts(),
344341
tuple(self.names), tuple(self.varnames),
345-
self.filename, self.name, self.firstlineno,
342+
self.filename, self.name, self.lnotab.firstline,
346343
self.lnotab.getTable())
347344

348345
def getConsts(self):
@@ -464,14 +461,16 @@ def findDepth(self, insts):
464461
if depth > maxDepth:
465462
maxDepth = depth
466463
# now check patterns
467-
for pat, delta in self.patterns:
464+
for pat, pat_delta in self.patterns:
468465
if opname[:len(pat)] == pat:
466+
delta = pat_delta
469467
depth = depth + delta
470468
break
471469
# if we still haven't found a match
472470
if delta == 0:
473-
meth = getattr(self, opname)
474-
depth = depth + meth(i[1])
471+
meth = getattr(self, opname, None)
472+
if meth is not None:
473+
depth = depth + meth(i[1])
475474
if depth < 0:
476475
depth = 0
477476
return maxDepth
@@ -527,6 +526,12 @@ def BUILD_LIST(self, count):
527526
def CALL_FUNCTION(self, argc):
528527
hi, lo = divmod(argc, 256)
529528
return lo + hi * 2
529+
def CALL_FUNCTION_VAR(self, argc):
530+
return self.CALL_FUNCTION(argc)+1
531+
def CALL_FUNCTION_KW(self, argc):
532+
return self.CALL_FUNCTION(argc)+1
533+
def CALL_FUNCTION_VAR_KW(self, argc):
534+
return self.CALL_FUNCTION(argc)+2
530535
def MAKE_FUNCTION(self, argc):
531536
return -argc
532537
def BUILD_SLICE(self, argc):

Tools/compiler/compiler/pycodegen.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
from compiler import pyassem, misc
1010
from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
1111

12+
callfunc_opcode_info = {
13+
# (Have *args, Have **args) : opcode
14+
(0,0) : "CALL_FUNCTION",
15+
(1,0) : "CALL_FUNCTION_VAR",
16+
(0,1) : "CALL_FUNCTION_KW",
17+
(1,1) : "CALL_FUNCTION_VAR_KW",
18+
}
19+
1220
def compile(filename):
1321
f = open(filename)
1422
buf = f.read()
@@ -478,7 +486,14 @@ def visitCallFunc(self, node):
478486
kw = kw + 1
479487
else:
480488
pos = pos + 1
481-
self.emit('CALL_FUNCTION', kw << 8 | pos)
489+
if node.star_args is not None:
490+
self.visit(node.star_args)
491+
if node.dstar_args is not None:
492+
self.visit(node.dstar_args)
493+
have_star = node.star_args is not None
494+
have_dstar = node.dstar_args is not None
495+
opcode = callfunc_opcode_info[have_star, have_dstar]
496+
self.emit(opcode, kw << 8 | pos)
482497

483498
def visitPrint(self, node):
484499
self.emit('SET_LINENO', node.lineno)

Tools/compiler/compiler/transformer.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,10 +984,32 @@ def com_call_function(self, primaryNode, nodelist):
984984
return Node('call_func', primaryNode, [ ])
985985
args = [ ]
986986
kw = 0
987-
for i in range(1, len(nodelist), 2):
988-
kw, result = self.com_argument(nodelist[i], kw)
987+
len_nodelist = len(nodelist)
988+
for i in range(1, len_nodelist, 2):
989+
node = nodelist[i]
990+
if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
991+
break
992+
kw, result = self.com_argument(node, kw)
989993
args.append(result)
990-
return Node('call_func', primaryNode, args)
994+
else:
995+
i = i + 1 # No broken by star arg, so skip the last one we processed.
996+
star_node = dstar_node = None
997+
while i < len_nodelist:
998+
tok = nodelist[i]
999+
ch = nodelist[i+1]
1000+
i = i + 3
1001+
if tok[0]==token.STAR:
1002+
if star_node is not None:
1003+
raise SyntaxError, 'already have the varargs indentifier'
1004+
star_node = self.com_node(ch)
1005+
elif tok[0]==token.DOUBLESTAR:
1006+
if dstar_node is not None:
1007+
raise SyntaxError, 'already have the kwargs indentifier'
1008+
dstar_node = self.com_node(ch)
1009+
else:
1010+
raise SyntaxError, 'unknown node type: %s' % tok
1011+
1012+
return Node('call_func', primaryNode, args, star_node, dstar_node)
9911013

9921014
def com_argument(self, nodelist, kw):
9931015
if len(nodelist) == 2:

0 commit comments

Comments
 (0)