[pypy-commit] pypy py3k: (antocuni, romain) implement keyword only args in the astbuilder
rguillebert
noreply at buildbot.pypy.org
Thu Jan 19 12:05:19 CET 2012
Author: Romain Guillebert <romain.py at gmail.com>
Branch: py3k
Changeset: r51475:27f5a4ae0d7d
Date: 2012-01-19 12:04 +0100
http://bitbucket.org/pypy/pypy/changeset/27f5a4ae0d7d/
Log: (antocuni, romain) implement keyword only args in the astbuilder
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -2280,18 +2280,22 @@
class arguments(AST):
- def __init__(self, args, vararg, kwarg, defaults):
+ def __init__(self, args, vararg, kwonlyargs, kwarg, defaults):
self.args = args
self.w_args = None
self.vararg = vararg
+ self.kwonlyargs = kwonlyargs
+ self.w_kwonlyargs = None
self.kwarg = kwarg
self.defaults = defaults
self.w_defaults = None
- self.initialization_state = 15
+ self.initialization_state = 31
def mutate_over(self, visitor):
if self.args:
visitor._mutate_sequence(self.args)
+ if self.kwonlyargs:
+ visitor._mutate_sequence(self.kwonlyargs)
if self.defaults:
visitor._mutate_sequence(self.defaults)
return visitor.visit_arguments(self)
@@ -2300,12 +2304,12 @@
visitor.visit_arguments(self)
def sync_app_attrs(self, space):
- if (self.initialization_state & ~6) ^ 9:
- self.missing_field(space, ['args', None, None, 'defaults'], 'arguments')
+ if (self.initialization_state & ~10) ^ 21:
+ self.missing_field(space, ['args', None, 'kwonlyargs', None, 'defaults'], 'arguments')
else:
if not self.initialization_state & 2:
self.vararg = None
- if not self.initialization_state & 4:
+ if not self.initialization_state & 8:
self.kwarg = None
w_list = self.w_args
if w_list is not None:
@@ -2317,6 +2321,16 @@
if self.args is not None:
for node in self.args:
node.sync_app_attrs(space)
+ w_list = self.w_kwonlyargs
+ if w_list is not None:
+ list_w = space.listview(w_list)
+ if list_w:
+ self.kwonlyargs = [space.interp_w(expr, w_obj) for w_obj in list_w]
+ else:
+ self.kwonlyargs = None
+ if self.kwonlyargs is not None:
+ for node in self.kwonlyargs:
+ node.sync_app_attrs(space)
w_list = self.w_defaults
if w_list is not None:
list_w = space.listview(w_list)
@@ -2727,6 +2741,7 @@
def visit_arguments(self, node):
self.visit_sequence(node.args)
+ self.visit_sequence(node.kwonlyargs)
self.visit_sequence(node.defaults)
def visit_keyword(self, node):
@@ -6908,12 +6923,29 @@
w_self.deldictvalue(space, 'vararg')
w_self.initialization_state |= 2
+def arguments_get_kwonlyargs(space, w_self):
+ if not w_self.initialization_state & 4:
+ typename = space.type(w_self).getname(space)
+ raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwonlyargs')
+ if w_self.w_kwonlyargs is None:
+ if w_self.kwonlyargs is None:
+ list_w = []
+ else:
+ list_w = [space.wrap(node) for node in w_self.kwonlyargs]
+ w_list = space.newlist(list_w)
+ w_self.w_kwonlyargs = w_list
+ return w_self.w_kwonlyargs
+
+def arguments_set_kwonlyargs(space, w_self, w_new_value):
+ w_self.w_kwonlyargs = w_new_value
+ w_self.initialization_state |= 4
+
def arguments_get_kwarg(space, w_self):
if w_self.w_dict is not None:
w_obj = w_self.getdictvalue(space, 'kwarg')
if w_obj is not None:
return w_obj
- if not w_self.initialization_state & 4:
+ if not w_self.initialization_state & 8:
typename = space.type(w_self).getname(space)
raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg')
return space.wrap(w_self.kwarg)
@@ -6930,10 +6962,10 @@
w_self.setdictvalue(space, 'kwarg', w_new_value)
return
w_self.deldictvalue(space, 'kwarg')
- w_self.initialization_state |= 4
+ w_self.initialization_state |= 8
def arguments_get_defaults(space, w_self):
- if not w_self.initialization_state & 8:
+ if not w_self.initialization_state & 16:
typename = space.type(w_self).getname(space)
raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults')
if w_self.w_defaults is None:
@@ -6947,17 +6979,18 @@
def arguments_set_defaults(space, w_self, w_new_value):
w_self.w_defaults = w_new_value
- w_self.initialization_state |= 8
-
-_arguments_field_unroller = unrolling_iterable(['args', 'vararg', 'kwarg', 'defaults'])
+ w_self.initialization_state |= 16
+
+_arguments_field_unroller = unrolling_iterable(['args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults'])
def arguments_init(space, w_self, __args__):
w_self = space.descr_self_interp_w(arguments, w_self)
w_self.w_args = None
+ w_self.w_kwonlyargs = None
w_self.w_defaults = None
args_w, kwargs_w = __args__.unpack()
if args_w:
- if len(args_w) != 4:
- w_err = space.wrap("arguments constructor takes either 0 or 4 positional arguments")
+ if len(args_w) != 5:
+ w_err = space.wrap("arguments constructor takes either 0 or 5 positional arguments")
raise OperationError(space.w_TypeError, w_err)
i = 0
for field in _arguments_field_unroller:
@@ -6969,9 +7002,10 @@
arguments.typedef = typedef.TypeDef("arguments",
AST.typedef,
__module__='_ast',
- _fields=_FieldsWrapper(['args', 'vararg', 'kwarg', 'defaults']),
+ _fields=_FieldsWrapper(['args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults']),
args=typedef.GetSetProperty(arguments_get_args, arguments_set_args, cls=arguments),
vararg=typedef.GetSetProperty(arguments_get_vararg, arguments_set_vararg, cls=arguments),
+ kwonlyargs=typedef.GetSetProperty(arguments_get_kwonlyargs, arguments_set_kwonlyargs, cls=arguments),
kwarg=typedef.GetSetProperty(arguments_get_kwarg, arguments_set_kwarg, cls=arguments),
defaults=typedef.GetSetProperty(arguments_get_defaults, arguments_set_defaults, cls=arguments),
__new__=interp2app(get_AST_new(arguments)),
diff --git a/pypy/interpreter/astcompiler/astbuilder.py b/pypy/interpreter/astcompiler/astbuilder.py
--- a/pypy/interpreter/astcompiler/astbuilder.py
+++ b/pypy/interpreter/astcompiler/astbuilder.py
@@ -508,13 +508,14 @@
# and varargslist (lambda definition).
if arguments_node.type == syms.parameters:
if len(arguments_node.children) == 2:
- return ast.arguments(None, None, None, None)
+ return ast.arguments(None, None, None, None, None)
arguments_node = arguments_node.children[1]
i = 0
child_count = len(arguments_node.children)
defaults = []
args = []
variable_arg = None
+ keywordonly_args = None
keywords_arg = None
have_default = False
while i < child_count:
@@ -552,13 +553,16 @@
self.check_forbidden_name(arg_name, name_node)
name = ast.Name(arg_name, ast.Param, name_node.lineno,
name_node.column)
- args.append(name)
+ if keywordonly_args is None:
+ args.append(name)
+ else:
+ keywordonly_args.append(name)
i += 2
break
elif arg_type == tokens.STAR:
name_node = arguments_node.children[i + 1]
+ keywordonly_args = []
if name_node.type == tokens.COMMA:
- # XXX for now
i += 2
else:
variable_arg = name_node.children[0].value
@@ -575,7 +579,7 @@
defaults = None
if not args:
args = None
- return ast.arguments(args, variable_arg, keywords_arg, defaults)
+ return ast.arguments(args, variable_arg, keywordonly_args, keywords_arg, defaults)
def handle_arg_unpacking(self, fplist_node):
args = []
@@ -775,7 +779,7 @@
def handle_lambdef(self, lambdef_node):
expr = self.handle_expr(lambdef_node.children[-1])
if len(lambdef_node.children) == 3:
- args = ast.arguments(None, None, None, None)
+ args = ast.arguments(None, None, None, None, None)
else:
args = self.handle_arguments(lambdef_node.children[1])
return ast.Lambda(args, expr, lambdef_node.lineno, lambdef_node.column)
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1185,3 +1185,17 @@
if1, if2 = comps[0].ifs
assert isinstance(if1, ast.Name)
assert isinstance(if2, ast.Name)
+
+ def test_kwonly_arguments(self):
+ fn = self.get_first_stmt("def f(a, b, c, *, kwarg): pass")
+ assert isinstance(fn, ast.FunctionDef)
+ assert len(fn.args.kwonlyargs) == 1
+ assert isinstance(fn.args.kwonlyargs[0], ast.expr)
+ assert fn.args.kwonlyargs[0].id == "kwarg"
+
+ def test_kwonly_arguments_2(self):
+ fn = self.get_first_stmt("def f(a, b, c, *args, kwarg): pass")
+ assert isinstance(fn, ast.FunctionDef)
+ assert len(fn.args.kwonlyargs) == 1
+ assert isinstance(fn.args.kwonlyargs[0], ast.expr)
+ assert fn.args.kwonlyargs[0].id == "kwarg"
diff --git a/pypy/interpreter/astcompiler/tools/Python.asdl b/pypy/interpreter/astcompiler/tools/Python.asdl
--- a/pypy/interpreter/astcompiler/tools/Python.asdl
+++ b/pypy/interpreter/astcompiler/tools/Python.asdl
@@ -105,7 +105,7 @@
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
attributes(int lineno, int col_offset)
- arguments = (expr* args, identifier? vararg,
+ arguments = (expr* args, identifier? vararg, expr* kwonlyargs,
identifier? kwarg, expr* defaults)
-- keyword arguments supplied to call
More information about the pypy-commit
mailing list