8000 Jiwon Seo's PEP 3102 implementation. · python/cpython@4f72a78 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f72a78

Browse files
committed
Jiwon Seo's PEP 3102 implementation.
See SF#1549670. The compiler package has not yet been updated.
1 parent fc2a0a8 commit 4f72a78

31 files changed

+739
-227
lines changed

Grammar/Grammar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ decorators: decorator+
2424
funcdef: [decorators] 'def' NAME parameters ':' suite
2525
parameters: '(' [varargslist] ')'
2626
varargslist: ((fpdef ['=' test] ',')*
27-
('*' NAME [',' '**' NAME] | '**' NAME) |
27+
('*' [NAME] (',' NAME ['=' test])* [',' '**' NAME] | '**' NAME) |
2828
fpdef ['=' test] (',' fpdef ['=' test])* [','])
2929
fpdef: NAME | '(' fplist ')'
3030
fplist: fpdef (',' fpdef)* [',']

Include/Python-ast.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,10 @@ struct _excepthandler {
328328
struct _arguments {
329329
asdl_seq *args;
330330
identifier vararg;
331+
asdl_seq *kwonlyargs;
331332
identifier kwarg;
332333
asdl_seq *defaults;
334+
asdl_seq *kw_defaults;
333335
};
334336

335337
struct _keyword {
@@ -427,8 +429,9 @@ comprehension_ty comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs,
427429
PyArena *arena);
428430
excepthandler_ty excepthandler(expr_ty type, expr_ty name, asdl_seq * body, int
429431
lineno, int col_offset, PyArena *arena);
430-
arguments_ty arguments(asdl_seq * args, identifier vararg, identifier kwarg,
431-
asdl_seq * defaults, PyArena *arena);
432+
arguments_ty arguments(asdl_seq * args, identifier vararg, asdl_seq *
433+
kwonlyargs, identifier kwarg, asdl_seq * defaults,
434+
asdl_seq * kw_defaults, PyArena *arena);
432435
keyword_ty keyword(identifier arg, expr_ty value, PyArena *arena);
433436
alias_ty alias(identifier name, identifier asname, PyArena *arena);
434437

Include/code.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ extern "C" {
1010
typedef struct {
1111
PyObject_HEAD
1212
int co_argcount; /* #arguments, except *args */
13+
int co_kwonlyargcount; /* #keyword only arguments */
1314
int co_nlocals; /* #local variables */
1415
int co_stacksize; /* #entries needed for evaluation stack */
1516
int co_flags; /* CO_..., see below */
@@ -63,8 +64,9 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
6364

6465
/* Public interface */
6566
PyAPI_FUNC(PyCodeObject *) PyCode_New(
66-
int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *,
67-
PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *);
67+
int, int, int, int, int, PyObject *, PyObject *,
68+
PyObject *, PyObject *, PyObject *, PyObject *,
69+
PyObject *, PyObject *, int, PyObject *);
6870
/* same as struct above */
6971
PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
7072

Include/eval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
1515
PyObject **args, int argc,
1616
PyObject **kwds, int kwdc,
1717
PyObject **defs, int defc,
18-
PyObject *closure);
18+
PyObject *kwdefs, PyObject *closure);
1919

2020
PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
2121

Include/funcobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ typedef struct {
2323
PyObject *func_code; /* A code object */
2424
PyObject *func_globals; /* A dictionary (other mappings won't do) */
2525
PyObject *func_defaults; /* NULL or a tuple */
26+
PyObject *func_kwdefaults; /* NULL or a dict */
2627
PyObject *func_closure; /* NULL or a tuple of cell objects */
2728
PyObject *func_doc; /* The __doc__ attribute, can be anything */
2829
PyObject *func_name; /* The __name__ attribute, a string object */
@@ -47,6 +48,8 @@ PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
4748
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
4849
PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *);
4950
PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *);
51+
PyAPI_FUNC(PyObject *) PyFunction_GetKwDefaults(PyObject *);
52+
PyAPI_FUNC(int) PyFunction_SetKwDefaults(PyObject *, PyObject *);
5053
PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *);
5154
PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *);
5255

@@ -60,6 +63,8 @@ PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *);
6063
(((PyFunctionObject *)func) -> func_module)
6164
#define PyFunction_GET_DEFAULTS(func) \
6265
(((PyFunctionObject *)func) -> func_defaults)
66+
#define PyFunction_GET_KW_DEFAULTS(func) \
67+
(((PyFunctionObject *)func) -> func_kwdefaults)
6368
#define PyFunction_GET_CLOSURE(func) \
6469
(((PyFunctionObject *)func) -> func_closure)
6570

Lib/compiler/ast.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -487,11 +487,12 @@ def __repr__(self):
487487
return "From(%s, %s, %s)" % (repr(self.modname), repr(self.names), repr(self.level))
488488

489489
class Function(Node):
490-
def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None):
490+
def __init__(self, decorators, name, argnames, defaults, kwonlyargs, flags, doc, code, lineno=None):
491491
self.decorators = decorators
492492
self.name = name
493493
self.argnames = argnames
494494
self.defaults = defaults
495+
self.kwonlyargs = kwonlyargs
495496
self.flags = flags
496497
self.doc = doc
497498
self.code = code
@@ -509,6 +510,7 @@ def getChildren(self):
509510
children.append(self.name)
510511
children.append(self.argnames)
511512
children.extend(flatten(self.defaults))
513+
children.append(self.kwonlyargs)
512514
children.append(self.flags)
513515
children.append(self.doc)
514516
children.append(self.code)
@@ -523,14 +525,15 @@ def getChildNodes(self):
523525
return tuple(nodelist)
524526

525527
def __repr__(self):
526-
return "Function(%s, %s, %s, %s, %s, %s, %s)" % (repr(self.decorators), repr(self.name), repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.doc), repr(self.code))
528+
return "Function(%s, %s, %s, %s, %s, %s, %s, %s)" % (repr(self.decorators), repr(self.name), repr(self.argnames), repr(self.defaults), repr(self.kwonlyargs), repr(self.flags), repr(self.doc), repr(self.code))
527529

528530
class GenExpr(Node):
529531
def __init__(self, code, lineno=None):
530532
self.code = code
531533
self.lineno = lineno
532534
self.argnames = ['.0']
533535
self.varargs = self.kwargs = None
536+
self.kwonlyargs = ()
534537

535538

536539
def getChildren(self):
@@ -713,9 +716,10 @@ def __repr__(self):
713716
return "Keyword(%s, %s)" % (repr(self.name), repr(self.expr))
714717

715718
class Lambda(Node):
716-
def __init__(self, argnames, defaults, flags, code, lineno=None):
719+
def __init__(self, argnames, defaults, kwonlyargs, flags, code, lineno=None):
717720
self.argnames = argnames
718721
self.defaults = defaults
722+
self.kwonlyargs = kwonlyargs
719723
self.flags = flags
720724
self.code = code
721725
self.lineno = lineno
@@ -730,6 +734,7 @@ def getChildren(self):
730734
children = []
731735
children.append(self.argnames)
732736
children.extend(flatten(self.defaults))
737+
children.append(self.kwonlyargs)
733738
children.append(self.flags)
734739
children.append(self.code)
735740
return tuple(children)
@@ -741,7 +746,7 @@ def getChildNodes(self):
741746
return tuple(nodelist)
742747

743748
def __repr__(self):
744-
return "Lambda(%s, %s, %s, %s)" % (repr(self.argnames), repr(self.defaults), repr(self.flags), repr(self.code))
749+
return "Lambda(%s, %s, %s, %s, %s)" % (repr(self.argnames), repr(self.defaults), repr(self.kwonlyargs), repr(self.flags), repr(self.code))
745750

746751
class LeftShift(Node):
747752
def __init__(self, (left, right), lineno=None):

Lib/compiler/pyassem.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,15 @@ def getContainedGraphs(self):
313313
class PyFlowGraph(FlowGraph):
314314
super_init = FlowGraph.__init__
315315

316-
def __init__(self, name, filename, args=(), optimized=0, klass=None):
316+
def __init__(self, name, filename,
317+
args=(), kwonlyargs={}, optimized=0, klass=None):
317318
self.super_init()
318319
self.name = name
319320
self.filename = filename
320321
self.docstring = None
321322
self.args = args # XXX
322323
self.argcount = getArgCount(args)
324+
self.kwonlyargs = kwonlyargs
323325
self.klass = klass
324326
if optimized:
325327
self.flags = CO_OPTIMIZED | CO_NEWLOCALS
@@ -595,7 +597,9 @@ def newCodeObject(self):
595597
argcount = self.argcount
596598
if self.flags & CO_VARKEYWORDS:
597599
argcount = argcount - 1
598-
return new.code(argcount, nlocals, self.stacksize, self.flags,
600+
kwonlyargcount = len(self.kwonlyargs)
601+
return new.code(argcount, kwonlyargcount,
602+
nlocals, self.stacksize, self.flags,
599603
self.lnotab.getCode(), self.getConsts(),
600604
tuple(self.names), tuple(self.varnames),
601605
self.filename, self.name, self.lnotab.firstline,
@@ -804,7 +808,8 @@ def CALL_FUNCTION_KW(self, argc):
804808
def CALL_FUNCTION_VAR_KW(self, argc):
805809
return self.CALL_FUNCTION(argc)-2
806810
def MAKE_FUNCTION(self, argc):
807-
return -argc
811+
hi, lo = divmod(argc, 256)
812+
return -(lo + hi * 2)
808813
def MAKE_CLOSURE(self, argc):
809814
# XXX need to account for free variables too!
810815
return -argc

Lib/compiler/pycodegen.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,12 @@ def _visitFuncOrLambda(self, node, isLambda=0):
378378
walk(node.code, gen)
379379
gen.finish()
380380
self.set_lineno(node)
381+
for keyword in node.kwonlyargs:
382+
default = keyword.expr
383+
if isinstance(default, ast.EmptyNode):
384+
continue
385+
self.emit('LOAD_CONST', keyword.name)
386+
self.visit(default)
381387
for default in node.defaults:
382388
self.visit(default)
383389
self._makeClosure(gen, len(node.defaults))
@@ -1320,7 +1326,9 @@ def __init__(self, func, scopes, isLambda, class_name, mod):
13201326
name = func.name
13211327

13221328
args, hasTupleArg = generateArgList(func.argnames)
1329+
kwonlyargs = generateKwonlyArgList(func.kwonlyargs)
13231330
self.graph = pyassem.PyFlowGraph(name, func.filename, args,
1331+
kwonlyargs=kwonlyargs,
13241332
optimized=1)
13251333
self.isLambda = isLambda
13261334
self.super_init()
@@ -1456,6 +1464,13 @@ def generateArgList(arglist):
14561464
raise ValueError, "unexpect argument type:", elt
14571465
return args + extra, count
14581466

1467+
def generateKwonlyArgList(keywordOnlyArgs):
1468+
kwonlyargs = {}
1469+
for elt in keywordOnlyArgs:
1470+
assert isinstance(elt, ast.Keyword)
1471+
kwonlyargs[elt.name] = elt.expr
1472+
return kwonlyargs
1473+
14591474
def findOp(node):
14601475
"""Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
14611476
v = OpFinder()

Lib/compiler/transformer.py

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,9 @@ def funcdef(self, nodelist):
250250
args = nodelist[-3][2]
251251

252252
if args[0] == symbol.varargslist:
253-
names, defaults, flags = self.com_arglist(args[1:])
253+
names, defaults, kwonlyargs, flags = self.com_arglist(args[1:])
254254
else:
255-
names = defaults = ()
255+
names = defaults = kwonlyargs = ()
256256
flags = 0
257257
doc = self.get_docstring(nodelist[-1])
258258

@@ -263,21 +263,23 @@ def funcdef(self, nodelist):
263263
assert isinstance(code, Stmt)
264264
assert isinstance(code.nodes[0], Discard)
265265
del code.nodes[0]
266-
return Function(decorators, name, names, defaults, flags, doc, code,
267-
lineno=lineno)
266+
return Function(decorators, name, names, defaults,
267+
kwonlyargs, flags, doc, code, lineno=lineno)
268268

269269
def lambdef(self, nodelist):
270270
# lambdef: 'lambda' [varargslist] ':' test
271271
if nodelist[2][0] == symbol.varargslist:
272-
names, defaults, flags = self.com_arglist(nodelist[2][1:])
272+
names, defaults, kwonlyargs, flags = \
273+
self.com_arglist(nodelist[2][1:])
273274
else:
274-
names = defaults = ()
275+
names = defaults = kwonlyargs = ()
275276
flags = 0
276277

277278
# code for lambda
278279
code = self.com_node(nodelist[-1])
279280

280-
return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])
281+
return Lambda(names, defaults, kwonlyargs,
282+
flags, code, lineno=nodelist[1][2])
281283
old_lambdef = lambdef
282284

283285
def classdef(self, nodelist):
@@ -783,13 +785,37 @@ def com_NEWLINE(self, *args):
783785
# ('const', xxxx)) Nodes)
784786
return Discard(Const(None))
785787

788+
def keywordonlyargs(self, nodelist):
789+
# (',' NAME ['=' test])*
790+
# ^^^
791+
# ------+
792+
kwonlyargs = []
793+
i = 0
794+
while i < len(nodelist):
795+
default = EmptyNode()
796+
node = nodelist[i]
797+
#assert node[0] == token.COMMA
798+
#node = nodelist[i+1]
799+
if i+1 < len(nodelist) and nodelist[i+1][0] == token.EQUAL:
800+
assert i+2 < len(nodelist)
801+
default = self.com_node(nodelist[i+2])
802+
i += 2
803+
if node[0] == token.DOUBLESTAR:
804+
return kwonlyargs, i
805+
elif node[0] == token.NAME:
806+
kwonlyargs.append(Keyword(node[1], default, lineno=node[2]))
807+
i += 2
808+
return kwonlyargs, i
809+
786810
def com_arglist(self, nodelist):
787811
# varargslist:
788-
# (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
789-
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
812+
# (fpdef ['=' test] ',')*
813+
# ('*' [NAME] (',' NAME '=' test)* [',' '**' NAME] | '**' NAME)
814+
# | fpdef ['=' test] (',' fpdef ['=' test])* [',']
790815
# fpdef: NAME | '(' fplist ')'
791816
# fplist: fpdef (',' fpdef)* [',']
792817
names = []
818+
kwonlyargs = []
793819
defaults = []
794820
flags = 0
795821

@@ -799,10 +825,22 @@ def com_arglist(self, nodelist):
799825
if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
800826
if node[0] == token.STAR:
801827
node = nodelist[i+1]
802-
if node[0] == token.NAME:
828+
if node[0] == token.NAME: # vararg
803829
names.append(node[1])
804830
flags = flags | CO_VARARGS
805831
i = i + 3
832+
else: # no vararg
833+
assert node[0] == token.COMMA
834+
i += 1
835+
#elif node[0] == token.COMMA:
836+
# i += 1
837+
# kwonlyargs, skip = self.keywordonlyargs(nodelist[i:])
838+
# i += skip
839+
if nodelist[i][0] == token.NAME:
840+
kwonlyargs, skip = self.keywordonlyargs(nodelist[i:])
841+
i += skip
842+
843+
print "kwonlyargs:", kwonlyargs
806844

807845
if i < len(nodelist):
808846
# should be DOUBLESTAR
@@ -831,7 +869,8 @@ def com_arglist(self, nodelist):
831869
# skip the comma
832870
i = i + 1
833871

834-
return names, defaults, flags
872+
print "names:", names, "defaults:", defaults, "kwonlyargs:", kwonlyargs, "flags:", flags
873+
return names, defaults, kwonlyargs, flags
835874

836875
def com_fpdef(self, node):
837876
# fpdef: NAME | '(' fplist ')'

0 commit comments

Comments
 (0)
0