17db96d56Sopenharmony_ci#-------------------------------------------------------------------------------
27db96d56Sopenharmony_ci# Parser for ASDL [1] definition files. Reads in an ASDL description and parses
37db96d56Sopenharmony_ci# it into an AST that describes it.
47db96d56Sopenharmony_ci#
57db96d56Sopenharmony_ci# The EBNF we're parsing here: Figure 1 of the paper [1]. Extended to support
67db96d56Sopenharmony_ci# modules and attributes after a product. Words starting with Capital letters
77db96d56Sopenharmony_ci# are terminals. Literal tokens are in "double quotes". Others are
87db96d56Sopenharmony_ci# non-terminals. Id is either TokenId or ConstructorId.
97db96d56Sopenharmony_ci#
107db96d56Sopenharmony_ci# module        ::= "module" Id "{" [definitions] "}"
117db96d56Sopenharmony_ci# definitions   ::= { TypeId "=" type }
127db96d56Sopenharmony_ci# type          ::= product | sum
137db96d56Sopenharmony_ci# product       ::= fields ["attributes" fields]
147db96d56Sopenharmony_ci# fields        ::= "(" { field, "," } field ")"
157db96d56Sopenharmony_ci# field         ::= TypeId ["?" | "*"] [Id]
167db96d56Sopenharmony_ci# sum           ::= constructor { "|" constructor } ["attributes" fields]
177db96d56Sopenharmony_ci# constructor   ::= ConstructorId [fields]
187db96d56Sopenharmony_ci#
197db96d56Sopenharmony_ci# [1] "The Zephyr Abstract Syntax Description Language" by Wang, et. al. See
207db96d56Sopenharmony_ci#     http://asdl.sourceforge.net/
217db96d56Sopenharmony_ci#-------------------------------------------------------------------------------
227db96d56Sopenharmony_cifrom collections import namedtuple
237db96d56Sopenharmony_ciimport re
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci__all__ = [
267db96d56Sopenharmony_ci    'builtin_types', 'parse', 'AST', 'Module', 'Type', 'Constructor',
277db96d56Sopenharmony_ci    'Field', 'Sum', 'Product', 'VisitorBase', 'Check', 'check']
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci# The following classes define nodes into which the ASDL description is parsed.
307db96d56Sopenharmony_ci# Note: this is a "meta-AST". ASDL files (such as Python.asdl) describe the AST
317db96d56Sopenharmony_ci# structure used by a programming language. But ASDL files themselves need to be
327db96d56Sopenharmony_ci# parsed. This module parses ASDL files and uses a simple AST to represent them.
337db96d56Sopenharmony_ci# See the EBNF at the top of the file to understand the logical connection
347db96d56Sopenharmony_ci# between the various node types.
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_cibuiltin_types = {'identifier', 'string', 'int', 'constant'}
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ciclass AST:
397db96d56Sopenharmony_ci    def __repr__(self):
407db96d56Sopenharmony_ci        raise NotImplementedError
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ciclass Module(AST):
437db96d56Sopenharmony_ci    def __init__(self, name, dfns):
447db96d56Sopenharmony_ci        self.name = name
457db96d56Sopenharmony_ci        self.dfns = dfns
467db96d56Sopenharmony_ci        self.types = {type.name: type.value for type in dfns}
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci    def __repr__(self):
497db96d56Sopenharmony_ci        return 'Module({0.name}, {0.dfns})'.format(self)
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ciclass Type(AST):
527db96d56Sopenharmony_ci    def __init__(self, name, value):
537db96d56Sopenharmony_ci        self.name = name
547db96d56Sopenharmony_ci        self.value = value
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ci    def __repr__(self):
577db96d56Sopenharmony_ci        return 'Type({0.name}, {0.value})'.format(self)
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ciclass Constructor(AST):
607db96d56Sopenharmony_ci    def __init__(self, name, fields=None):
617db96d56Sopenharmony_ci        self.name = name
627db96d56Sopenharmony_ci        self.fields = fields or []
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci    def __repr__(self):
657db96d56Sopenharmony_ci        return 'Constructor({0.name}, {0.fields})'.format(self)
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ciclass Field(AST):
687db96d56Sopenharmony_ci    def __init__(self, type, name=None, seq=False, opt=False):
697db96d56Sopenharmony_ci        self.type = type
707db96d56Sopenharmony_ci        self.name = name
717db96d56Sopenharmony_ci        self.seq = seq
727db96d56Sopenharmony_ci        self.opt = opt
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci    def __str__(self):
757db96d56Sopenharmony_ci        if self.seq:
767db96d56Sopenharmony_ci            extra = "*"
777db96d56Sopenharmony_ci        elif self.opt:
787db96d56Sopenharmony_ci            extra = "?"
797db96d56Sopenharmony_ci        else:
807db96d56Sopenharmony_ci            extra = ""
817db96d56Sopenharmony_ci
827db96d56Sopenharmony_ci        return "{}{} {}".format(self.type, extra, self.name)
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci    def __repr__(self):
857db96d56Sopenharmony_ci        if self.seq:
867db96d56Sopenharmony_ci            extra = ", seq=True"
877db96d56Sopenharmony_ci        elif self.opt:
887db96d56Sopenharmony_ci            extra = ", opt=True"
897db96d56Sopenharmony_ci        else:
907db96d56Sopenharmony_ci            extra = ""
917db96d56Sopenharmony_ci        if self.name is None:
927db96d56Sopenharmony_ci            return 'Field({0.type}{1})'.format(self, extra)
937db96d56Sopenharmony_ci        else:
947db96d56Sopenharmony_ci            return 'Field({0.type}, {0.name}{1})'.format(self, extra)
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ciclass Sum(AST):
977db96d56Sopenharmony_ci    def __init__(self, types, attributes=None):
987db96d56Sopenharmony_ci        self.types = types
997db96d56Sopenharmony_ci        self.attributes = attributes or []
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci    def __repr__(self):
1027db96d56Sopenharmony_ci        if self.attributes:
1037db96d56Sopenharmony_ci            return 'Sum({0.types}, {0.attributes})'.format(self)
1047db96d56Sopenharmony_ci        else:
1057db96d56Sopenharmony_ci            return 'Sum({0.types})'.format(self)
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ciclass Product(AST):
1087db96d56Sopenharmony_ci    def __init__(self, fields, attributes=None):
1097db96d56Sopenharmony_ci        self.fields = fields
1107db96d56Sopenharmony_ci        self.attributes = attributes or []
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci    def __repr__(self):
1137db96d56Sopenharmony_ci        if self.attributes:
1147db96d56Sopenharmony_ci            return 'Product({0.fields}, {0.attributes})'.format(self)
1157db96d56Sopenharmony_ci        else:
1167db96d56Sopenharmony_ci            return 'Product({0.fields})'.format(self)
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci# A generic visitor for the meta-AST that describes ASDL. This can be used by
1197db96d56Sopenharmony_ci# emitters. Note that this visitor does not provide a generic visit method, so a
1207db96d56Sopenharmony_ci# subclass needs to define visit methods from visitModule to as deep as the
1217db96d56Sopenharmony_ci# interesting node.
1227db96d56Sopenharmony_ci# We also define a Check visitor that makes sure the parsed ASDL is well-formed.
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ciclass VisitorBase(object):
1257db96d56Sopenharmony_ci    """Generic tree visitor for ASTs."""
1267db96d56Sopenharmony_ci    def __init__(self):
1277db96d56Sopenharmony_ci        self.cache = {}
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci    def visit(self, obj, *args):
1307db96d56Sopenharmony_ci        klass = obj.__class__
1317db96d56Sopenharmony_ci        meth = self.cache.get(klass)
1327db96d56Sopenharmony_ci        if meth is None:
1337db96d56Sopenharmony_ci            methname = "visit" + klass.__name__
1347db96d56Sopenharmony_ci            meth = getattr(self, methname, None)
1357db96d56Sopenharmony_ci            self.cache[klass] = meth
1367db96d56Sopenharmony_ci        if meth:
1377db96d56Sopenharmony_ci            try:
1387db96d56Sopenharmony_ci                meth(obj, *args)
1397db96d56Sopenharmony_ci            except Exception as e:
1407db96d56Sopenharmony_ci                print("Error visiting %r: %s" % (obj, e))
1417db96d56Sopenharmony_ci                raise
1427db96d56Sopenharmony_ci
1437db96d56Sopenharmony_ciclass Check(VisitorBase):
1447db96d56Sopenharmony_ci    """A visitor that checks a parsed ASDL tree for correctness.
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci    Errors are printed and accumulated.
1477db96d56Sopenharmony_ci    """
1487db96d56Sopenharmony_ci    def __init__(self):
1497db96d56Sopenharmony_ci        super(Check, self).__init__()
1507db96d56Sopenharmony_ci        self.cons = {}
1517db96d56Sopenharmony_ci        self.errors = 0
1527db96d56Sopenharmony_ci        self.types = {}
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci    def visitModule(self, mod):
1557db96d56Sopenharmony_ci        for dfn in mod.dfns:
1567db96d56Sopenharmony_ci            self.visit(dfn)
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci    def visitType(self, type):
1597db96d56Sopenharmony_ci        self.visit(type.value, str(type.name))
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci    def visitSum(self, sum, name):
1627db96d56Sopenharmony_ci        for t in sum.types:
1637db96d56Sopenharmony_ci            self.visit(t, name)
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_ci    def visitConstructor(self, cons, name):
1667db96d56Sopenharmony_ci        key = str(cons.name)
1677db96d56Sopenharmony_ci        conflict = self.cons.get(key)
1687db96d56Sopenharmony_ci        if conflict is None:
1697db96d56Sopenharmony_ci            self.cons[key] = name
1707db96d56Sopenharmony_ci        else:
1717db96d56Sopenharmony_ci            print('Redefinition of constructor {}'.format(key))
1727db96d56Sopenharmony_ci            print('Defined in {} and {}'.format(conflict, name))
1737db96d56Sopenharmony_ci            self.errors += 1
1747db96d56Sopenharmony_ci        for f in cons.fields:
1757db96d56Sopenharmony_ci            self.visit(f, key)
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci    def visitField(self, field, name):
1787db96d56Sopenharmony_ci        key = str(field.type)
1797db96d56Sopenharmony_ci        l = self.types.setdefault(key, [])
1807db96d56Sopenharmony_ci        l.append(name)
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci    def visitProduct(self, prod, name):
1837db96d56Sopenharmony_ci        for f in prod.fields:
1847db96d56Sopenharmony_ci            self.visit(f, name)
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_cidef check(mod):
1877db96d56Sopenharmony_ci    """Check the parsed ASDL tree for correctness.
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci    Return True if success. For failure, the errors are printed out and False
1907db96d56Sopenharmony_ci    is returned.
1917db96d56Sopenharmony_ci    """
1927db96d56Sopenharmony_ci    v = Check()
1937db96d56Sopenharmony_ci    v.visit(mod)
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci    for t in v.types:
1967db96d56Sopenharmony_ci        if t not in mod.types and not t in builtin_types:
1977db96d56Sopenharmony_ci            v.errors += 1
1987db96d56Sopenharmony_ci            uses = ", ".join(v.types[t])
1997db96d56Sopenharmony_ci            print('Undefined type {}, used in {}'.format(t, uses))
2007db96d56Sopenharmony_ci    return not v.errors
2017db96d56Sopenharmony_ci
2027db96d56Sopenharmony_ci# The ASDL parser itself comes next. The only interesting external interface
2037db96d56Sopenharmony_ci# here is the top-level parse function.
2047db96d56Sopenharmony_ci
2057db96d56Sopenharmony_cidef parse(filename):
2067db96d56Sopenharmony_ci    """Parse ASDL from the given file and return a Module node describing it."""
2077db96d56Sopenharmony_ci    with open(filename, encoding="utf-8") as f:
2087db96d56Sopenharmony_ci        parser = ASDLParser()
2097db96d56Sopenharmony_ci        return parser.parse(f.read())
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci# Types for describing tokens in an ASDL specification.
2127db96d56Sopenharmony_ciclass TokenKind:
2137db96d56Sopenharmony_ci    """TokenKind is provides a scope for enumerated token kinds."""
2147db96d56Sopenharmony_ci    (ConstructorId, TypeId, Equals, Comma, Question, Pipe, Asterisk,
2157db96d56Sopenharmony_ci     LParen, RParen, LBrace, RBrace) = range(11)
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    operator_table = {
2187db96d56Sopenharmony_ci        '=': Equals, ',': Comma,    '?': Question, '|': Pipe,    '(': LParen,
2197db96d56Sopenharmony_ci        ')': RParen, '*': Asterisk, '{': LBrace,   '}': RBrace}
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ciToken = namedtuple('Token', 'kind value lineno')
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ciclass ASDLSyntaxError(Exception):
2247db96d56Sopenharmony_ci    def __init__(self, msg, lineno=None):
2257db96d56Sopenharmony_ci        self.msg = msg
2267db96d56Sopenharmony_ci        self.lineno = lineno or '<unknown>'
2277db96d56Sopenharmony_ci
2287db96d56Sopenharmony_ci    def __str__(self):
2297db96d56Sopenharmony_ci        return 'Syntax error on line {0.lineno}: {0.msg}'.format(self)
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_cidef tokenize_asdl(buf):
2327db96d56Sopenharmony_ci    """Tokenize the given buffer. Yield Token objects."""
2337db96d56Sopenharmony_ci    for lineno, line in enumerate(buf.splitlines(), 1):
2347db96d56Sopenharmony_ci        for m in re.finditer(r'\s*(\w+|--.*|.)', line.strip()):
2357db96d56Sopenharmony_ci            c = m.group(1)
2367db96d56Sopenharmony_ci            if c[0].isalpha():
2377db96d56Sopenharmony_ci                # Some kind of identifier
2387db96d56Sopenharmony_ci                if c[0].isupper():
2397db96d56Sopenharmony_ci                    yield Token(TokenKind.ConstructorId, c, lineno)
2407db96d56Sopenharmony_ci                else:
2417db96d56Sopenharmony_ci                    yield Token(TokenKind.TypeId, c, lineno)
2427db96d56Sopenharmony_ci            elif c[:2] == '--':
2437db96d56Sopenharmony_ci                # Comment
2447db96d56Sopenharmony_ci                break
2457db96d56Sopenharmony_ci            else:
2467db96d56Sopenharmony_ci                # Operators
2477db96d56Sopenharmony_ci                try:
2487db96d56Sopenharmony_ci                    op_kind = TokenKind.operator_table[c]
2497db96d56Sopenharmony_ci                except KeyError:
2507db96d56Sopenharmony_ci                    raise ASDLSyntaxError('Invalid operator %s' % c, lineno)
2517db96d56Sopenharmony_ci                yield Token(op_kind, c, lineno)
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ciclass ASDLParser:
2547db96d56Sopenharmony_ci    """Parser for ASDL files.
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci    Create, then call the parse method on a buffer containing ASDL.
2577db96d56Sopenharmony_ci    This is a simple recursive descent parser that uses tokenize_asdl for the
2587db96d56Sopenharmony_ci    lexing.
2597db96d56Sopenharmony_ci    """
2607db96d56Sopenharmony_ci    def __init__(self):
2617db96d56Sopenharmony_ci        self._tokenizer = None
2627db96d56Sopenharmony_ci        self.cur_token = None
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_ci    def parse(self, buf):
2657db96d56Sopenharmony_ci        """Parse the ASDL in the buffer and return an AST with a Module root.
2667db96d56Sopenharmony_ci        """
2677db96d56Sopenharmony_ci        self._tokenizer = tokenize_asdl(buf)
2687db96d56Sopenharmony_ci        self._advance()
2697db96d56Sopenharmony_ci        return self._parse_module()
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci    def _parse_module(self):
2727db96d56Sopenharmony_ci        if self._at_keyword('module'):
2737db96d56Sopenharmony_ci            self._advance()
2747db96d56Sopenharmony_ci        else:
2757db96d56Sopenharmony_ci            raise ASDLSyntaxError(
2767db96d56Sopenharmony_ci                'Expected "module" (found {})'.format(self.cur_token.value),
2777db96d56Sopenharmony_ci                self.cur_token.lineno)
2787db96d56Sopenharmony_ci        name = self._match(self._id_kinds)
2797db96d56Sopenharmony_ci        self._match(TokenKind.LBrace)
2807db96d56Sopenharmony_ci        defs = self._parse_definitions()
2817db96d56Sopenharmony_ci        self._match(TokenKind.RBrace)
2827db96d56Sopenharmony_ci        return Module(name, defs)
2837db96d56Sopenharmony_ci
2847db96d56Sopenharmony_ci    def _parse_definitions(self):
2857db96d56Sopenharmony_ci        defs = []
2867db96d56Sopenharmony_ci        while self.cur_token.kind == TokenKind.TypeId:
2877db96d56Sopenharmony_ci            typename = self._advance()
2887db96d56Sopenharmony_ci            self._match(TokenKind.Equals)
2897db96d56Sopenharmony_ci            type = self._parse_type()
2907db96d56Sopenharmony_ci            defs.append(Type(typename, type))
2917db96d56Sopenharmony_ci        return defs
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci    def _parse_type(self):
2947db96d56Sopenharmony_ci        if self.cur_token.kind == TokenKind.LParen:
2957db96d56Sopenharmony_ci            # If we see a (, it's a product
2967db96d56Sopenharmony_ci            return self._parse_product()
2977db96d56Sopenharmony_ci        else:
2987db96d56Sopenharmony_ci            # Otherwise it's a sum. Look for ConstructorId
2997db96d56Sopenharmony_ci            sumlist = [Constructor(self._match(TokenKind.ConstructorId),
3007db96d56Sopenharmony_ci                                   self._parse_optional_fields())]
3017db96d56Sopenharmony_ci            while self.cur_token.kind  == TokenKind.Pipe:
3027db96d56Sopenharmony_ci                # More constructors
3037db96d56Sopenharmony_ci                self._advance()
3047db96d56Sopenharmony_ci                sumlist.append(Constructor(
3057db96d56Sopenharmony_ci                                self._match(TokenKind.ConstructorId),
3067db96d56Sopenharmony_ci                                self._parse_optional_fields()))
3077db96d56Sopenharmony_ci            return Sum(sumlist, self._parse_optional_attributes())
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci    def _parse_product(self):
3107db96d56Sopenharmony_ci        return Product(self._parse_fields(), self._parse_optional_attributes())
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_ci    def _parse_fields(self):
3137db96d56Sopenharmony_ci        fields = []
3147db96d56Sopenharmony_ci        self._match(TokenKind.LParen)
3157db96d56Sopenharmony_ci        while self.cur_token.kind == TokenKind.TypeId:
3167db96d56Sopenharmony_ci            typename = self._advance()
3177db96d56Sopenharmony_ci            is_seq, is_opt = self._parse_optional_field_quantifier()
3187db96d56Sopenharmony_ci            id = (self._advance() if self.cur_token.kind in self._id_kinds
3197db96d56Sopenharmony_ci                                  else None)
3207db96d56Sopenharmony_ci            fields.append(Field(typename, id, seq=is_seq, opt=is_opt))
3217db96d56Sopenharmony_ci            if self.cur_token.kind == TokenKind.RParen:
3227db96d56Sopenharmony_ci                break
3237db96d56Sopenharmony_ci            elif self.cur_token.kind == TokenKind.Comma:
3247db96d56Sopenharmony_ci                self._advance()
3257db96d56Sopenharmony_ci        self._match(TokenKind.RParen)
3267db96d56Sopenharmony_ci        return fields
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci    def _parse_optional_fields(self):
3297db96d56Sopenharmony_ci        if self.cur_token.kind == TokenKind.LParen:
3307db96d56Sopenharmony_ci            return self._parse_fields()
3317db96d56Sopenharmony_ci        else:
3327db96d56Sopenharmony_ci            return None
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci    def _parse_optional_attributes(self):
3357db96d56Sopenharmony_ci        if self._at_keyword('attributes'):
3367db96d56Sopenharmony_ci            self._advance()
3377db96d56Sopenharmony_ci            return self._parse_fields()
3387db96d56Sopenharmony_ci        else:
3397db96d56Sopenharmony_ci            return None
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    def _parse_optional_field_quantifier(self):
3427db96d56Sopenharmony_ci        is_seq, is_opt = False, False
3437db96d56Sopenharmony_ci        if self.cur_token.kind == TokenKind.Asterisk:
3447db96d56Sopenharmony_ci            is_seq = True
3457db96d56Sopenharmony_ci            self._advance()
3467db96d56Sopenharmony_ci        elif self.cur_token.kind == TokenKind.Question:
3477db96d56Sopenharmony_ci            is_opt = True
3487db96d56Sopenharmony_ci            self._advance()
3497db96d56Sopenharmony_ci        return is_seq, is_opt
3507db96d56Sopenharmony_ci
3517db96d56Sopenharmony_ci    def _advance(self):
3527db96d56Sopenharmony_ci        """ Return the value of the current token and read the next one into
3537db96d56Sopenharmony_ci            self.cur_token.
3547db96d56Sopenharmony_ci        """
3557db96d56Sopenharmony_ci        cur_val = None if self.cur_token is None else self.cur_token.value
3567db96d56Sopenharmony_ci        try:
3577db96d56Sopenharmony_ci            self.cur_token = next(self._tokenizer)
3587db96d56Sopenharmony_ci        except StopIteration:
3597db96d56Sopenharmony_ci            self.cur_token = None
3607db96d56Sopenharmony_ci        return cur_val
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    _id_kinds = (TokenKind.ConstructorId, TokenKind.TypeId)
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci    def _match(self, kind):
3657db96d56Sopenharmony_ci        """The 'match' primitive of RD parsers.
3667db96d56Sopenharmony_ci
3677db96d56Sopenharmony_ci        * Verifies that the current token is of the given kind (kind can
3687db96d56Sopenharmony_ci          be a tuple, in which the kind must match one of its members).
3697db96d56Sopenharmony_ci        * Returns the value of the current token
3707db96d56Sopenharmony_ci        * Reads in the next token
3717db96d56Sopenharmony_ci        """
3727db96d56Sopenharmony_ci        if (isinstance(kind, tuple) and self.cur_token.kind in kind or
3737db96d56Sopenharmony_ci            self.cur_token.kind == kind
3747db96d56Sopenharmony_ci            ):
3757db96d56Sopenharmony_ci            value = self.cur_token.value
3767db96d56Sopenharmony_ci            self._advance()
3777db96d56Sopenharmony_ci            return value
3787db96d56Sopenharmony_ci        else:
3797db96d56Sopenharmony_ci            raise ASDLSyntaxError(
3807db96d56Sopenharmony_ci                'Unmatched {} (found {})'.format(kind, self.cur_token.kind),
3817db96d56Sopenharmony_ci                self.cur_token.lineno)
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    def _at_keyword(self, keyword):
3847db96d56Sopenharmony_ci        return (self.cur_token.kind == TokenKind.TypeId and
3857db96d56Sopenharmony_ci                self.cur_token.value == keyword)
386