diff --git a/Parser/Python.asdl b/Parser/Python.asdl index db61d8b1f66..96f3914b029 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -63,7 +63,7 @@ module Python | UnaryOp(unaryop op, expr operand) | Lambda(arguments args, expr body) | IfExp(expr test, expr body, expr orelse) - | Dict(expr* keys, expr* values) + | Dict(expr?* keys, expr* values) | Set(expr* elts) | ListComp(expr elt, comprehension* generators) | SetComp(expr elt, comprehension* generators) diff --git a/Parser/asdl.py b/Parser/asdl.py index e3e6c34d2a9..7a9c9d8628d 100644 --- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -12,7 +12,7 @@ # type ::= product | sum # product ::= fields ["attributes" fields] # fields ::= "(" { field, "," } field ")" -# field ::= TypeId ["?" | "*"] [Id] +# field ::= TypeId { "?" | "*" } [Id] # sum ::= constructor { "|" constructor } ["attributes" fields] # constructor ::= ConstructorId [fields] # @@ -20,6 +20,7 @@ # http://asdl.sourceforge.net/ #------------------------------------------------------------------------------- from collections import namedtuple +import enum import re __all__ = [ @@ -64,34 +65,43 @@ class Constructor(AST): def __repr__(self): return 'Constructor({0.name}, {0.fields})'.format(self) +class Quantifier(enum.Enum): + OPTIONAL = enum.auto() + SEQUENCE = enum.auto() + class Field(AST): - def __init__(self, type, name=None, seq=False, opt=False): + def __init__(self, type, name=None, quantifiers=None): self.type = type self.name = name - self.seq = seq - self.opt = opt + self.seq = False + self.opt = False + self.quantifiers = quantifiers or [] + if len(self.quantifiers) > 0: + self.seq = self.quantifiers[-1] is Quantifier.SEQUENCE + self.opt = self.quantifiers[-1] is Quantifier.OPTIONAL def __str__(self): - if self.seq: - extra = "*" - elif self.opt: - extra = "?" - else: - extra = "" + extra = "" + for mod in self.quantifiers: + if mod is Quantifier.SEQUENCE: + extra += "*" + elif mod is Quantifier.OPTIONAL: + extra += "?" return "{}{} {}".format(self.type, extra, self.name) def __repr__(self): - if self.seq: - extra = ", seq=True" - elif self.opt: - extra = ", opt=True" - else: - extra = "" + extra = "" + for mod in self.quantifiers: + if mod is Quantifier.SEQUENCE: + extra += ", SEQUENCE" + elif mod is Quantifier.OPTIONAL: + extra += ", OPTIONAL" + if self.name is None: - return 'Field({0.type}{1})'.format(self, extra) + return 'Field({0.type}, quantifiers=[{1}])'.format(self, extra) else: - return 'Field({0.type}, {0.name}{1})'.format(self, extra) + return 'Field({0.type}, {0.name}, quantifiers=[{1}])'.format(self, extra) class Sum(AST): def __init__(self, types, attributes=None): @@ -314,10 +324,10 @@ class ASDLParser: self._match(TokenKind.LParen) while self.cur_token.kind == TokenKind.TypeId: typename = self._advance() - is_seq, is_opt = self._parse_optional_field_quantifier() + quantifiers = self._parse_optional_field_quantifier() id = (self._advance() if self.cur_token.kind in self._id_kinds else None) - fields.append(Field(typename, id, seq=is_seq, opt=is_opt)) + fields.append(Field(typename, id, quantifiers=quantifiers)) if self.cur_token.kind == TokenKind.RParen: break elif self.cur_token.kind == TokenKind.Comma: @@ -339,14 +349,14 @@ class ASDLParser: return None def _parse_optional_field_quantifier(self): - is_seq, is_opt = False, False - if self.cur_token.kind == TokenKind.Asterisk: - is_seq = True + quantifiers = [] + while self.cur_token.kind in (TokenKind.Asterisk, TokenKind.Question): + if self.cur_token.kind == TokenKind.Asterisk: + quantifiers.append(Quantifier.SEQUENCE) + elif self.cur_token.kind == TokenKind.Question: + quantifiers.append(Quantifier.OPTIONAL) self._advance() - elif self.cur_token.kind == TokenKind.Question: - is_opt = True - self._advance() - return is_seq, is_opt + return quantifiers def _advance(self): """ Return the value of the current token and read the next one into diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 94d9a76d283..df035568f84 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -6362,7 +6362,7 @@ init_types(void *arg) " | UnaryOp(unaryop op, expr operand)\n" " | Lambda(arguments args, expr body)\n" " | IfExp(expr test, expr body, expr orelse)\n" - " | Dict(expr* keys, expr* values)\n" + " | Dict(expr?* keys, expr* values)\n" " | Set(expr* elts)\n" " | ListComp(expr elt, comprehension* generators)\n" " | SetComp(expr elt, comprehension* generators)\n" @@ -6419,7 +6419,7 @@ init_types(void *arg) if (!state->IfExp_type) return -1; state->Dict_type = make_type(state, "Dict", state->expr_type, Dict_fields, 2, - "Dict(expr* keys, expr* values)"); + "Dict(expr?* keys, expr* values)"); if (!state->Dict_type) return -1; state->Set_type = make_type(state, "Set", state->expr_type, Set_fields, 1, "Set(expr* elts)");