Author: Romain Guillebert <romain...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit