Best Python code snippet using gherkin-python
__init__.py
Source:__init__.py  
1"""Python Enumerations"""2import sys as _sys3__all__ = ['Enum', 'IntEnum', 'unique']4version = 1, 1, 65pyver = float('%s.%s' % _sys.version_info[:2])6try:7    any8except NameError:9    def any(iterable):10        for element in iterable:11            if element:12                return True13        return False14try:15    from collections import OrderedDict16except ImportError:17    OrderedDict = None18try:19    basestring20except NameError:21    # In Python 2 basestring is the ancestor of both str and unicode22    # in Python 3 it's just str, but was missing in 3.123    basestring = str24try:25    unicode26except NameError:27    # In Python 3 unicode no longer exists (it's just str)28    unicode = str29class _RouteClassAttributeToGetattr(object):30    """Route attribute access on a class to __getattr__.31    This is a descriptor, used to define attributes that act differently when32    accessed through an instance and through a class.  Instance access remains33    normal, but access to an attribute through a class will be routed to the34    class's __getattr__ method; this is done by raising AttributeError.35    """36    def __init__(self, fget=None):37        self.fget = fget38    def __get__(self, instance, ownerclass=None):39        if instance is None:40            raise AttributeError()41        return self.fget(instance)42    def __set__(self, instance, value):43        raise AttributeError("can't set attribute")44    def __delete__(self, instance):45        raise AttributeError("can't delete attribute")46def _is_descriptor(obj):47    """Returns True if obj is a descriptor, False otherwise."""48    return (49            hasattr(obj, '__get__') or50            hasattr(obj, '__set__') or51            hasattr(obj, '__delete__'))52def _is_dunder(name):53    """Returns True if a __dunder__ name, False otherwise."""54    return (name[:2] == name[-2:] == '__' and55            name[2:3] != '_' and56            name[-3:-2] != '_' and57            len(name) > 4)58def _is_sunder(name):59    """Returns True if a _sunder_ name, False otherwise."""60    return (name[0] == name[-1] == '_' and61            name[1:2] != '_' and62            name[-2:-1] != '_' and63            len(name) > 2)64def _make_class_unpicklable(cls):65    """Make the given class un-picklable."""66    def _break_on_call_reduce(self, protocol=None):67        raise TypeError('%r cannot be pickled' % self)68    cls.__reduce_ex__ = _break_on_call_reduce69    cls.__module__ = '<unknown>'70class _EnumDict(dict):71    """Track enum member order and ensure member names are not reused.72    EnumMeta will use the names found in self._member_names as the73    enumeration member names.74    """75    def __init__(self):76        super(_EnumDict, self).__init__()77        self._member_names = []78    def __setitem__(self, key, value):79        """Changes anything not dundered or not a descriptor.80        If a descriptor is added with the same name as an enum member, the name81        is removed from _member_names (this may leave a hole in the numerical82        sequence of values).83        If an enum member name is used twice, an error is raised; duplicate84        values are not checked for.85        Single underscore (sunder) names are reserved.86        Note:   in 3.x __order__ is simply discarded as a not necessary piece87                leftover from 2.x88        """89        if pyver >= 3.0 and key in ('_order_', '__order__'):90            return91        elif key == '__order__':92            key = '_order_'93        if _is_sunder(key):94            if key != '_order_':95                raise ValueError('_names_ are reserved for future Enum use')96        elif _is_dunder(key):97            pass98        elif key in self._member_names:99            # descriptor overwriting an enum?100            raise TypeError('Attempted to reuse key: %r' % key)101        elif not _is_descriptor(value):102            if key in self:103                # enum overwriting a descriptor?104                raise TypeError('Key already defined as: %r' % self[key])105            self._member_names.append(key)106        super(_EnumDict, self).__setitem__(key, value)107# Dummy value for Enum as EnumMeta explicity checks for it, but of course until108# EnumMeta finishes running the first time the Enum class doesn't exist.  This109# is also why there are checks in EnumMeta like `if Enum is not None`110Enum = None111class EnumMeta(type):112    """Metaclass for Enum"""113    @classmethod114    def __prepare__(metacls, cls, bases):115        return _EnumDict()116    def __new__(metacls, cls, bases, classdict):117        # an Enum class is final once enumeration items have been defined; it118        # cannot be mixed with other types (int, float, etc.) if it has an119        # inherited __new__ unless a new __new__ is defined (or the resulting120        # class will fail).121        if type(classdict) is dict:122            original_dict = classdict123            classdict = _EnumDict()124            for k, v in original_dict.items():125                classdict[k] = v126        member_type, first_enum = metacls._get_mixins_(bases)127        __new__, save_new, use_args = metacls._find_new_(classdict, member_type,128                                                        first_enum)129        # save enum items into separate mapping so they don't get baked into130        # the new class131        members = dict((k, classdict[k]) for k in classdict._member_names)132        for name in classdict._member_names:133            del classdict[name]134        # py2 support for definition order135        _order_ = classdict.get('_order_')136        if _order_ is None:137            if pyver < 3.0:138                try:139                    _order_ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])]140                except TypeError:141                    _order_ = [name for name in sorted(members.keys())]142            else:143                _order_ = classdict._member_names144        else:145            del classdict['_order_']146            if pyver < 3.0:147                _order_ = _order_.replace(',', ' ').split()148                aliases = [name for name in members if name not in _order_]149                _order_ += aliases150        # check for illegal enum names (any others?)151        invalid_names = set(members) & set(['mro'])152        if invalid_names:153            raise ValueError('Invalid enum member name(s): %s' % (154                ', '.join(invalid_names), ))155        # save attributes from super classes so we know if we can take156        # the shortcut of storing members in the class dict157        base_attributes = set([a for b in bases for a in b.__dict__])158        # create our new Enum type159        enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict)160        enum_class._member_names_ = []               # names in random order161        if OrderedDict is not None:162            enum_class._member_map_ = OrderedDict()163        else:164            enum_class._member_map_ = {}             # name->value map165        enum_class._member_type_ = member_type166        # Reverse value->name map for hashable values.167        enum_class._value2member_map_ = {}168        # instantiate them, checking for duplicates as we go169        # we instantiate first instead of checking for duplicates first in case170        # a custom __new__ is doing something funky with the values -- such as171        # auto-numbering ;)172        if __new__ is None:173            __new__ = enum_class.__new__174        for member_name in _order_:175            value = members[member_name]176            if not isinstance(value, tuple):177                args = (value, )178            else:179                args = value180            if member_type is tuple:   # special case for tuple enums181                args = (args, )     # wrap it one more time182            if not use_args or not args:183                enum_member = __new__(enum_class)184                if not hasattr(enum_member, '_value_'):185                    enum_member._value_ = value186            else:187                enum_member = __new__(enum_class, *args)188                if not hasattr(enum_member, '_value_'):189                    enum_member._value_ = member_type(*args)190            value = enum_member._value_191            enum_member._name_ = member_name192            enum_member.__objclass__ = enum_class193            enum_member.__init__(*args)194            # If another member with the same value was already defined, the195            # new member becomes an alias to the existing one.196            for name, canonical_member in enum_class._member_map_.items():197                if canonical_member.value == enum_member._value_:198                    enum_member = canonical_member199                    break200            else:201                # Aliases don't appear in member names (only in __members__).202                enum_class._member_names_.append(member_name)203            # performance boost for any member that would not shadow204            # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr)205            if member_name not in base_attributes:206                setattr(enum_class, member_name, enum_member)207            # now add to _member_map_208            enum_class._member_map_[member_name] = enum_member209            try:210                # This may fail if value is not hashable. We can't add the value211                # to the map, and by-value lookups for this value will be212                # linear.213                enum_class._value2member_map_[value] = enum_member214            except TypeError:215                pass216        # If a custom type is mixed into the Enum, and it does not know how217        # to pickle itself, pickle.dumps will succeed but pickle.loads will218        # fail.  Rather than have the error show up later and possibly far219        # from the source, sabotage the pickle protocol for this class so220        # that pickle.dumps also fails.221        #222        # However, if the new class implements its own __reduce_ex__, do not223        # sabotage -- it's on them to make sure it works correctly.  We use224        # __reduce_ex__ instead of any of the others as it is preferred by225        # pickle over __reduce__, and it handles all pickle protocols.226        unpicklable = False227        if '__reduce_ex__' not in classdict:228            if member_type is not object:229                methods = ('__getnewargs_ex__', '__getnewargs__',230                        '__reduce_ex__', '__reduce__')231                if not any(m in member_type.__dict__ for m in methods):232                    _make_class_unpicklable(enum_class)233                    unpicklable = True234        # double check that repr and friends are not the mixin's or various235        # things break (such as pickle)236        for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):237            class_method = getattr(enum_class, name)238            obj_method = getattr(member_type, name, None)239            enum_method = getattr(first_enum, name, None)240            if name not in classdict and class_method is not enum_method:241                if name == '__reduce_ex__' and unpicklable:242                    continue243                setattr(enum_class, name, enum_method)244        # method resolution and int's are not playing nice245        # Python's less than 2.6 use __cmp__246        if pyver < 2.6:247            if issubclass(enum_class, int):248                setattr(enum_class, '__cmp__', getattr(int, '__cmp__'))249        elif pyver < 3.0:250            if issubclass(enum_class, int):251                for method in (252                        '__le__',253                        '__lt__',254                        '__gt__',255                        '__ge__',256                        '__eq__',257                        '__ne__',258                        '__hash__',259                        ):260                    setattr(enum_class, method, getattr(int, method))261        # replace any other __new__ with our own (as long as Enum is not None,262        # anyway) -- again, this is to support pickle263        if Enum is not None:264            # if the user defined their own __new__, save it before it gets265            # clobbered in case they subclass later266            if save_new:267                setattr(enum_class, '__member_new__', enum_class.__dict__['__new__'])268            setattr(enum_class, '__new__', Enum.__dict__['__new__'])269        return enum_class270    def __bool__(cls):271        """272        classes/types should always be True.273        """274        return True275    def __call__(cls, value, names=None, module=None, type=None, start=1):276        """Either returns an existing member, or creates a new enum class.277        This method is used both when an enum class is given a value to match278        to an enumeration member (i.e. Color(3)) and for the functional API279        (i.e. Color = Enum('Color', names='red green blue')).280        When used for the functional API: `module`, if set, will be stored in281        the new class' __module__ attribute; `type`, if set, will be mixed in282        as the first base class.283        Note: if `module` is not set this routine will attempt to discover the284        calling module by walking the frame stack; if this is unsuccessful285        the resulting class will not be pickleable.286        """287        if names is None:  # simple value lookup288            return cls.__new__(cls, value)289        # otherwise, functional API: we're creating a new Enum type290        return cls._create_(value, names, module=module, type=type, start=start)291    def __contains__(cls, member):292        return isinstance(member, cls) and member.name in cls._member_map_293    def __delattr__(cls, attr):294        # nicer error message when someone tries to delete an attribute295        # (see issue19025).296        if attr in cls._member_map_:297            raise AttributeError(298                    "%s: cannot delete Enum member." % cls.__name__)299        super(EnumMeta, cls).__delattr__(attr)300    def __dir__(self):301        return (['__class__', '__doc__', '__members__', '__module__'] +302                self._member_names_)303    @property304    def __members__(cls):305        """Returns a mapping of member name->value.306        This mapping lists all enum members, including aliases. Note that this307        is a copy of the internal mapping.308        """309        return cls._member_map_.copy()310    def __getattr__(cls, name):311        """Return the enum member matching `name`312        We use __getattr__ instead of descriptors or inserting into the enum313        class' __dict__ in order to support `name` and `value` being both314        properties for enum members (which live in the class' __dict__) and315        enum members themselves.316        """317        if _is_dunder(name):318            raise AttributeError(name)319        try:320            return cls._member_map_[name]321        except KeyError:322            raise AttributeError(name)323    def __getitem__(cls, name):324        return cls._member_map_[name]325    def __iter__(cls):326        return (cls._member_map_[name] for name in cls._member_names_)327    def __reversed__(cls):328        return (cls._member_map_[name] for name in reversed(cls._member_names_))329    def __len__(cls):330        return len(cls._member_names_)331    __nonzero__ = __bool__332    def __repr__(cls):333        return "<enum %r>" % cls.__name__334    def __setattr__(cls, name, value):335        """Block attempts to reassign Enum members.336        A simple assignment to the class namespace only changes one of the337        several possible ways to get an Enum member from the Enum class,338        resulting in an inconsistent Enumeration.339        """340        member_map = cls.__dict__.get('_member_map_', {})341        if name in member_map:342            raise AttributeError('Cannot reassign members.')343        super(EnumMeta, cls).__setattr__(name, value)344    def _create_(cls, class_name, names=None, module=None, type=None, start=1):345        """Convenience method to create a new Enum class.346        `names` can be:347        * A string containing member names, separated either with spaces or348          commas.  Values are auto-numbered from 1.349        * An iterable of member names.  Values are auto-numbered from 1.350        * An iterable of (member name, value) pairs.351        * A mapping of member name -> value.352        """353        if pyver < 3.0:354            # if class_name is unicode, attempt a conversion to ASCII355            if isinstance(class_name, unicode):356                try:357                    class_name = class_name.encode('ascii')358                except UnicodeEncodeError:359                    raise TypeError('%r is not representable in ASCII' % class_name)360        metacls = cls.__class__361        if type is None:362            bases = (cls, )363        else:364            bases = (type, cls)365        classdict = metacls.__prepare__(class_name, bases)366        _order_ = []367        # special processing needed for names?368        if isinstance(names, basestring):369            names = names.replace(',', ' ').split()370        if isinstance(names, (tuple, list)) and isinstance(names[0], basestring):371            names = [(e, i+start) for (i, e) in enumerate(names)]372        # Here, names is either an iterable of (name, value) or a mapping.373        item = None  # in case names is empty374        for item in names:375            if isinstance(item, basestring):376                member_name, member_value = item, names[item]377            else:378                member_name, member_value = item379            classdict[member_name] = member_value380            _order_.append(member_name)381        # only set _order_ in classdict if name/value was not from a mapping382        if not isinstance(item, basestring):383            classdict['_order_'] = ' '.join(_order_)384        enum_class = metacls.__new__(metacls, class_name, bases, classdict)385        # TODO: replace the frame hack if a blessed way to know the calling386        # module is ever developed387        if module is None:388            try:389                module = _sys._getframe(2).f_globals['__name__']390            except (AttributeError, ValueError):391                pass392        if module is None:393            _make_class_unpicklable(enum_class)394        else:395            enum_class.__module__ = module396        return enum_class397    @staticmethod398    def _get_mixins_(bases):399        """Returns the type for creating enum members, and the first inherited400        enum class.401        bases: the tuple of bases that was given to __new__402        """403        if not bases or Enum is None:404            return object, Enum405        # double check that we are not subclassing a class with existing406        # enumeration members; while we're at it, see if any other data407        # type has been mixed in so we can use the correct __new__408        member_type = first_enum = None409        for base in bases:410            if  (base is not Enum and411                    issubclass(base, Enum) and412                    base._member_names_):413                raise TypeError("Cannot extend enumerations")414        # base is now the last base in bases415        if not issubclass(base, Enum):416            raise TypeError("new enumerations must be created as "417                    "`ClassName([mixin_type,] enum_type)`")418        # get correct mix-in type (either mix-in type of Enum subclass, or419        # first base if last base is Enum)420        if not issubclass(bases[0], Enum):421            member_type = bases[0]     # first data type422            first_enum = bases[-1]  # enum type423        else:424            for base in bases[0].__mro__:425                # most common: (IntEnum, int, Enum, object)426                # possible:    (<Enum 'AutoIntEnum'>, <Enum 'IntEnum'>,427                #               <class 'int'>, <Enum 'Enum'>,428                #               <class 'object'>)429                if issubclass(base, Enum):430                    if first_enum is None:431                        first_enum = base432                else:433                    if member_type is None:434                        member_type = base435        return member_type, first_enum436    if pyver < 3.0:437        @staticmethod438        def _find_new_(classdict, member_type, first_enum):439            """Returns the __new__ to be used for creating the enum members.440            classdict: the class dictionary given to __new__441            member_type: the data type whose __new__ will be used by default442            first_enum: enumeration to check for an overriding __new__443            """444            # now find the correct __new__, checking to see of one was defined445            # by the user; also check earlier enum classes in case a __new__ was446            # saved as __member_new__447            __new__ = classdict.get('__new__', None)448            if __new__:449                return None, True, True      # __new__, save_new, use_args450            N__new__ = getattr(None, '__new__')451            O__new__ = getattr(object, '__new__')452            if Enum is None:453                E__new__ = N__new__454            else:455                E__new__ = Enum.__dict__['__new__']456            # check all possibles for __member_new__ before falling back to457            # __new__458            for method in ('__member_new__', '__new__'):459                for possible in (member_type, first_enum):460                    try:461                        target = possible.__dict__[method]462                    except (AttributeError, KeyError):463                        target = getattr(possible, method, None)464                    if target not in [465                            None,466                            N__new__,467                            O__new__,468                            E__new__,469                            ]:470                        if method == '__member_new__':471                            classdict['__new__'] = target472                            return None, False, True473                        if isinstance(target, staticmethod):474                            target = target.__get__(member_type)475                        __new__ = target476                        break477                if __new__ is not None:478                    break479            else:480                __new__ = object.__new__481            # if a non-object.__new__ is used then whatever value/tuple was482            # assigned to the enum member name will be passed to __new__ and to the483            # new enum member's __init__484            if __new__ is object.__new__:485                use_args = False486            else:487                use_args = True488            return __new__, False, use_args489    else:490        @staticmethod491        def _find_new_(classdict, member_type, first_enum):492            """Returns the __new__ to be used for creating the enum members.493            classdict: the class dictionary given to __new__494            member_type: the data type whose __new__ will be used by default495            first_enum: enumeration to check for an overriding __new__496            """497            # now find the correct __new__, checking to see of one was defined498            # by the user; also check earlier enum classes in case a __new__ was499            # saved as __member_new__500            __new__ = classdict.get('__new__', None)501            # should __new__ be saved as __member_new__ later?502            save_new = __new__ is not None503            if __new__ is None:504                # check all possibles for __member_new__ before falling back to505                # __new__506                for method in ('__member_new__', '__new__'):507                    for possible in (member_type, first_enum):508                        target = getattr(possible, method, None)509                        if target not in (510                                None,511                                None.__new__,512                                object.__new__,513                                Enum.__new__,514                                ):515                            __new__ = target516                            break517                    if __new__ is not None:518                        break519                else:520                    __new__ = object.__new__521            # if a non-object.__new__ is used then whatever value/tuple was522            # assigned to the enum member name will be passed to __new__ and to the523            # new enum member's __init__524            if __new__ is object.__new__:525                use_args = False526            else:527                use_args = True528            return __new__, save_new, use_args529########################################################530# In order to support Python 2 and 3 with a single531# codebase we have to create the Enum methods separately532# and then use the `type(name, bases, dict)` method to533# create the class.534########################################################535temp_enum_dict = {}536temp_enum_dict['__doc__'] = "Generic enumeration.\n\n    Derive from this class to define new enumerations.\n\n"537def __new__(cls, value):538    # all enum instances are actually created during class construction539    # without calling this method; this method is called by the metaclass'540    # __call__ (i.e. Color(3) ), and by pickle541    if type(value) is cls:542        # For lookups like Color(Color.red)543        value = value.value544        #return value545    # by-value search for a matching enum member546    # see if it's in the reverse mapping (for hashable values)547    try:548        if value in cls._value2member_map_:549            return cls._value2member_map_[value]550    except TypeError:551        # not there, now do long search -- O(n) behavior552        for member in cls._member_map_.values():553            if member.value == value:554                return member555    raise ValueError("%s is not a valid %s" % (value, cls.__name__))556temp_enum_dict['__new__'] = __new__557del __new__558def __repr__(self):559    return "<%s.%s: %r>" % (560            self.__class__.__name__, self._name_, self._value_)561temp_enum_dict['__repr__'] = __repr__562del __repr__563def __str__(self):564    return "%s.%s" % (self.__class__.__name__, self._name_)565temp_enum_dict['__str__'] = __str__566del __str__567if pyver >= 3.0:568    def __dir__(self):569        added_behavior = [570                m571                for cls in self.__class__.mro()572                for m in cls.__dict__573                if m[0] != '_' and m not in self._member_map_574                ]575        return (['__class__', '__doc__', '__module__', ] + added_behavior)576    temp_enum_dict['__dir__'] = __dir__577    del __dir__578def __format__(self, format_spec):579    # mixed-in Enums should use the mixed-in type's __format__, otherwise580    # we can get strange results with the Enum name showing up instead of581    # the value582    # pure Enum branch583    if self._member_type_ is object:584        cls = str585        val = str(self)586    # mix-in branch587    else:588        cls = self._member_type_589        val = self.value590    return cls.__format__(val, format_spec)591temp_enum_dict['__format__'] = __format__592del __format__593####################################594# Python's less than 2.6 use __cmp__595if pyver < 2.6:596    def __cmp__(self, other):597        if type(other) is self.__class__:598            if self is other:599                return 0600            return -1601        return NotImplemented602        raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__))603    temp_enum_dict['__cmp__'] = __cmp__604    del __cmp__605else:606    def __le__(self, other):607        raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__))608    temp_enum_dict['__le__'] = __le__609    del __le__610    def __lt__(self, other):611        raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__))612    temp_enum_dict['__lt__'] = __lt__613    del __lt__614    def __ge__(self, other):615        raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__))616    temp_enum_dict['__ge__'] = __ge__617    del __ge__618    def __gt__(self, other):619        raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__))620    temp_enum_dict['__gt__'] = __gt__621    del __gt__622def __eq__(self, other):623    if type(other) is self.__class__:624        return self is other625    return NotImplemented626temp_enum_dict['__eq__'] = __eq__627del __eq__628def __ne__(self, other):629    if type(other) is self.__class__:630        return self is not other631    return NotImplemented632temp_enum_dict['__ne__'] = __ne__633del __ne__634def __hash__(self):635    return hash(self._name_)636temp_enum_dict['__hash__'] = __hash__637del __hash__638def __reduce_ex__(self, proto):639    return self.__class__, (self._value_, )640temp_enum_dict['__reduce_ex__'] = __reduce_ex__641del __reduce_ex__642# _RouteClassAttributeToGetattr is used to provide access to the `name`643# and `value` properties of enum members while keeping some measure of644# protection from modification, while still allowing for an enumeration645# to have members named `name` and `value`.  This works because enumeration646# members are not set directly on the enum class -- __getattr__ is647# used to look them up.648@_RouteClassAttributeToGetattr649def name(self):650    return self._name_651temp_enum_dict['name'] = name652del name653@_RouteClassAttributeToGetattr654def value(self):655    return self._value_656temp_enum_dict['value'] = value657del value658@classmethod659def _convert(cls, name, module, filter, source=None):660    """661    Create a new Enum subclass that replaces a collection of global constants662    """663    # convert all constants from source (or module) that pass filter() to664    # a new Enum called name, and export the enum and its members back to665    # module;666    # also, replace the __reduce_ex__ method so unpickling works in667    # previous Python versions668    module_globals = vars(_sys.modules[module])669    if source:670        source = vars(source)671    else:672        source = module_globals673    members = dict((name, value) for name, value in source.items() if filter(name))674    cls = cls(name, members, module=module)675    cls.__reduce_ex__ = _reduce_ex_by_name676    module_globals.update(cls.__members__)677    module_globals[name] = cls678    return cls679temp_enum_dict['_convert'] = _convert680del _convert681Enum = EnumMeta('Enum', (object, ), temp_enum_dict)682del temp_enum_dict683# Enum has now been created684###########################685class IntEnum(int, Enum):686    """Enum where members are also (and must be) ints"""687def _reduce_ex_by_name(self, proto):688    return self.name689def unique(enumeration):690    """Class decorator that ensures only unique members exist in an enumeration."""691    duplicates = []692    for name, member in enumeration.__members__.items():693        if name != member.name:694            duplicates.append((name, member.name))695    if duplicates:696        duplicate_names = ', '.join(697                ["%s -> %s" % (alias, name) for (alias, name) in duplicates]698                )699        raise ValueError('duplicate names found in %r: %s' %700                (enumeration, duplicate_names)701                )...java_cpp_enum_tests.py
Source:java_cpp_enum_tests.py  
1#!/usr/bin/env python2# Copyright 2014 The Chromium Authors. All rights reserved.3# Use of this source code is governed by a BSD-style license that can be4# found in the LICENSE file.5"""Tests for enum_preprocess.py.6This test suite contains various tests for the C++ -> Java enum generator.7"""8import collections9from datetime import date10import unittest11import java_cpp_enum12from java_cpp_enum import EnumDefinition, GenerateOutput13from java_cpp_enum import HeaderParser14from util import java_cpp_utils15class TestPreprocess(unittest.TestCase):16  def testOutput(self):17    definition = EnumDefinition(original_enum_name='ClassName',18                                enum_package='some.package',19                                entries=[('E1', 1), ('E2', '2 << 2')],20                                comments=[('E2', 'This is a comment.'),21                                          ('E1', 'This is a multiple line '22                                                 'comment that is really long. '23                                                 'This is a multiple line '24                                                 'comment that is really '25                                                 'really long.')])26    output = GenerateOutput('path/to/file', definition)27    expected = """28// Copyright %d The Chromium Authors. All rights reserved.29// Use of this source code is governed by a BSD-style license that can be30// found in the LICENSE file.31// This file is autogenerated by32//     %s33// From34//     path/to/file35package some.package;36import androidx.annotation.IntDef;37import java.lang.annotation.Retention;38import java.lang.annotation.RetentionPolicy;39@IntDef({40    ClassName.E1, ClassName.E241})42@Retention(RetentionPolicy.SOURCE)43public @interface ClassName {44  /**45   * %s46   * really really long.47   */48  int E1 = 1;49  /**50   * This is a comment.51   */52  int E2 = 2 << 2;53}54"""55    long_comment = ('This is a multiple line comment that is really long. '56                    'This is a multiple line comment that is')57    self.assertEqual(58        expected % (date.today().year, java_cpp_utils.GetScriptName(),59                    long_comment), output)60  def testParseSimpleEnum(self):61    test_data = """62      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace63      enum EnumName {64        VALUE_ZERO,65        VALUE_ONE,66      };67    """.split('\n')68    definitions = HeaderParser(test_data).ParseDefinitions()69    self.assertEqual(1, len(definitions))70    definition = definitions[0]71    self.assertEqual('EnumName', definition.class_name)72    self.assertEqual('test.namespace', definition.enum_package)73    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', 0),74                                              ('VALUE_ONE', 1)]),75                     definition.entries)76  def testParseBitShifts(self):77    test_data = """78      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace79      enum EnumName {80        VALUE_ZERO = 1 << 0,81        VALUE_ONE = 1 << 1,82      };83      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace84      enum EnumName {85        ENUM_NAME_ZERO = 1 << 0,86        ENUM_NAME_ONE = 1 << 1,87        ENUM_NAME_TWO = ENUM_NAME_ZERO | ENUM_NAME_ONE,88      };89    """.split('\n')90    definitions = HeaderParser(test_data).ParseDefinitions()91    self.assertEqual(2, len(definitions))92    definition = definitions[0]93    self.assertEqual('EnumName', definition.class_name)94    self.assertEqual('test.namespace', definition.enum_package)95    self.assertEqual(collections.OrderedDict([('VALUE_ZERO', '1 << 0'),96                                              ('VALUE_ONE', '1 << 1')]),97                     definition.entries)98    definition = definitions[1]99    expected_entries = collections.OrderedDict([100        ('ZERO', '1 << 0'),101        ('ONE', '1 << 1'),102        ('TWO', 'ZERO | ONE')])103    self.assertEqual(expected_entries, definition.entries)104  def testParseMultilineEnumEntry(self):105    test_data = """106      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace107      enum Foo {108        VALUE_ZERO = 1 << 0,109        VALUE_ONE =110            SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | ControlKey,111        VALUE_TWO = 1 << 18,112      };113    """.split('\n')114    expected_entries = collections.OrderedDict([115        ('VALUE_ZERO', '1 << 0'),116        ('VALUE_ONE', 'SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | '117         'ControlKey'),118        ('VALUE_TWO', '1 << 18')])119    definitions = HeaderParser(test_data).ParseDefinitions()120    self.assertEqual(1, len(definitions))121    definition = definitions[0]122    self.assertEqual('Foo', definition.class_name)123    self.assertEqual('bar.namespace', definition.enum_package)124    self.assertEqual(expected_entries, definition.entries)125  def testParseEnumEntryWithTrailingMultilineEntry(self):126    test_data = """127      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace128      enum Foo {129        VALUE_ZERO = 1,130        VALUE_ONE =131            SymbolKey | FnKey | AltGrKey | MetaKey |132            AltKey | ControlKey | ShiftKey,133      };134    """.split('\n')135    expected_entries = collections.OrderedDict([136        ('VALUE_ZERO', '1'),137        ('VALUE_ONE', 'SymbolKey | FnKey | AltGrKey | MetaKey | AltKey | '138         'ControlKey | ShiftKey')])139    definitions = HeaderParser(test_data).ParseDefinitions()140    self.assertEqual(1, len(definitions))141    definition = definitions[0]142    self.assertEqual('Foo', definition.class_name)143    self.assertEqual('bar.namespace', definition.enum_package)144    self.assertEqual(expected_entries, definition.entries)145  def testParseNoCommaAfterLastEntry(self):146    test_data = """147      // GENERATED_JAVA_ENUM_PACKAGE: bar.namespace148      enum Foo {149        VALUE_ZERO = 1,150        // This is a multiline151        //152        // comment with an empty line.153        VALUE_ONE = 2154      };155    """.split('\n')156    expected_entries = collections.OrderedDict([157        ('VALUE_ZERO', '1'),158        ('VALUE_ONE', '2')])159    expected_comments = collections.OrderedDict([160        ('VALUE_ONE', 'This is a multiline comment with an empty line.')])161    definitions = HeaderParser(test_data).ParseDefinitions()162    self.assertEqual(1, len(definitions))163    definition = definitions[0]164    self.assertEqual('Foo', definition.class_name)165    self.assertEqual('bar.namespace', definition.enum_package)166    self.assertEqual(expected_entries, definition.entries)167    self.assertEqual(expected_comments, definition.comments)168  def testParseClassNameOverride(self):169    test_data = """170      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace171      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName172      enum EnumName {173        FOO174      };175      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace176      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OtherOverride177      enum PrefixTest {178        PREFIX_TEST_A,179        PREFIX_TEST_B,180      };181    """.split('\n')182    definitions = HeaderParser(test_data).ParseDefinitions()183    self.assertEqual(2, len(definitions))184    definition = definitions[0]185    self.assertEqual('OverrideName', definition.class_name)186    definition = definitions[1]187    self.assertEqual('OtherOverride', definition.class_name)188    self.assertEqual(collections.OrderedDict([('A', 0),189                                              ('B', 1)]),190                     definition.entries)191  def testParsePreservesCommentsWhenPrefixStripping(self):192    test_data = """193      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace194      enum EnumOne {195        ENUM_ONE_A = 1,196        // Comment there197        ENUM_ONE_B = A,198      };199      enum EnumIgnore {200        C, D, E201      };202      // GENERATED_JAVA_ENUM_PACKAGE: other.package203      // GENERATED_JAVA_PREFIX_TO_STRIP: P_204      enum EnumTwo {205        P_A,206        // This comment spans207        // two lines.208        P_B209      };210    """.split('\n')211    definitions = HeaderParser(test_data).ParseDefinitions()212    self.assertEqual(2, len(definitions))213    definition = definitions[0]214    self.assertEqual('EnumOne', definition.class_name)215    self.assertEqual('test.namespace', definition.enum_package)216    self.assertEqual(collections.OrderedDict([('A', '1'),217                                              ('B', 'A')]),218                     definition.entries)219    self.assertEqual(collections.OrderedDict([('B', 'Comment there')]),220                     definition.comments)221    definition = definitions[1]222    self.assertEqual('EnumTwo', definition.class_name)223    self.assertEqual('other.package', definition.enum_package)224    self.assertEqual(collections.OrderedDict(225        [('B', 'This comment spans two lines.')]), definition.comments)226    self.assertEqual(collections.OrderedDict([('A', 0),227                                              ('B', 1)]),228                     definition.entries)229  def testParseTwoEnums(self):230    test_data = """231      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace232      enum AnEnum {233        ENUM_ONE_A = 1,234        ENUM_ONE_B = A,235      };236      enum EnumIgnore {237        C, D, E238      };239      // GENERATED_JAVA_ENUM_PACKAGE: other.package240      enum EnumTwo {241        P_A,242        P_B243      };244    """.split('\n')245    definitions = HeaderParser(test_data).ParseDefinitions()246    self.assertEqual(2, len(definitions))247    definition = definitions[0]248    self.assertEqual('AnEnum', definition.class_name)249    self.assertEqual('test.namespace', definition.enum_package)250    self.assertEqual(collections.OrderedDict([('ENUM_ONE_A', '1'),251                                              ('ENUM_ONE_B', 'A')]),252                     definition.entries)253    definition = definitions[1]254    self.assertEqual('EnumTwo', definition.class_name)255    self.assertEqual('other.package', definition.enum_package)256    self.assertEqual(collections.OrderedDict([('P_A', 0),257                                              ('P_B', 1)]),258                     definition.entries)259  def testParseSingleLineEnum(self):260    test_data = """261      // GENERATED_JAVA_ENUM_PACKAGE: other.package262      // GENERATED_JAVA_PREFIX_TO_STRIP: P_263      enum EnumTwo { P_A, P_B };264    """.split('\n')265    definitions = HeaderParser(test_data).ParseDefinitions()266    definition = definitions[0]267    self.assertEqual('EnumTwo', definition.class_name)268    self.assertEqual('other.package', definition.enum_package)269    self.assertEqual(collections.OrderedDict([('A', 0),270                                              ('B', 1)]),271                     definition.entries)272  def testParseWithStrippingAndRelativeReferences(self):273    test_data = """274      // GENERATED_JAVA_ENUM_PACKAGE: other.package275      // GENERATED_JAVA_PREFIX_TO_STRIP: P_276      enum EnumTwo {277        P_A = 1,278        // P_A is old-don't use P_A.279        P_B = P_A,280      };281    """.split('\n')282    definitions = HeaderParser(test_data).ParseDefinitions()283    definition = definitions[0]284    self.assertEqual('EnumTwo', definition.class_name)285    self.assertEqual('other.package', definition.enum_package)286    self.assertEqual(collections.OrderedDict([('A', '1'),287                                              ('B', 'A')]),288                     definition.entries)289    self.assertEqual(collections.OrderedDict([('B', 'A is old-don\'t use A.')]),290                     definition.comments)291  def testParseSingleLineAndRegularEnum(self):292    test_data = """293      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace294      enum EnumOne {295        ENUM_ONE_A = 1,296        // Comment there297        ENUM_ONE_B = A,298      };299      // GENERATED_JAVA_ENUM_PACKAGE: other.package300      enum EnumTwo { P_A, P_B };301      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace302      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName303      enum EnumName {304        ENUM_NAME_FOO305      };306    """.split('\n')307    definitions = HeaderParser(test_data).ParseDefinitions()308    definition = definitions[0]309    self.assertEqual(310        collections.OrderedDict([('A', '1'), ('B', 'A')]), definition.entries)311    self.assertEqual(collections.OrderedDict([('B', 'Comment there')]),312                     definition.comments)313    self.assertEqual(3, len(definitions))314    definition = definitions[1]315    self.assertEqual(316        collections.OrderedDict([('P_A', 0), ('P_B', 1)]), definition.entries)317    definition = definitions[2]318    self.assertEqual(collections.OrderedDict([('FOO', 0)]), definition.entries)319  def testParseWithCamelCaseNames(self):320    test_data = """321      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace322      enum EnumTest {323        EnumTestA = 1,324        // comment for EnumTestB.325        EnumTestB = 2,326      };327      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace328      // GENERATED_JAVA_PREFIX_TO_STRIP: Test329      enum AnEnum {330        TestHTTPOption,331        TestHTTPSOption,332      };333    """.split('\n')334    definitions = HeaderParser(test_data).ParseDefinitions()335    definition = definitions[0]336    self.assertEqual(337        collections.OrderedDict([('A', '1'), ('B', '2')]),338        definition.entries)339    self.assertEqual(340        collections.OrderedDict([('B', 'comment for B.')]),341        definition.comments)342    definition = definitions[1]343    self.assertEqual(344        collections.OrderedDict([('HTTP_OPTION', 0), ('HTTPS_OPTION', 1)]),345        definition.entries)346  def testParseWithKCamelCaseNames(self):347    test_data = """348      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace349      enum EnumOne {350        kEnumOne = 1,351        // comment for kEnumTwo.352        kEnumTwo = 2,353      };354      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace355      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName356      enum EnumName {357        kEnumNameFoo,358        kEnumNameBar359      };360      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace361      enum EnumName {362        kEnumNameFoo,363        kEnumBar,364      };365      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace366      enum Keys {367        kSymbolKey = 1 << 0,368        kAltKey = 1 << 1,369        kUpKey = 1 << 2,370        kKeyModifiers = kSymbolKey | kAltKey | kUpKey | kKeyModifiers,371      };372      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace373      enum Mixed {374        kTestVal,375        kCodecMPEG2376      };377    """.split('\n')378    definitions = HeaderParser(test_data).ParseDefinitions()379    definition = definitions[0]380    self.assertEqual(381        collections.OrderedDict([('ENUM_ONE', '1'), ('ENUM_TWO', '2')]),382        definition.entries)383    self.assertEqual(384        collections.OrderedDict([('ENUM_TWO', 'comment for ENUM_TWO.')]),385        definition.comments)386    definition = definitions[1]387    self.assertEqual(388        collections.OrderedDict([('FOO', 0), ('BAR', 1)]),389        definition.entries)390    definition = definitions[2]391    self.assertEqual(392        collections.OrderedDict([('ENUM_NAME_FOO', 0), ('ENUM_BAR', 1)]),393        definition.entries)394    definition = definitions[3]395    expected_entries = collections.OrderedDict([396        ('SYMBOL_KEY', '1 << 0'),397        ('ALT_KEY', '1 << 1'),398        ('UP_KEY', '1 << 2'),399        ('KEY_MODIFIERS', 'SYMBOL_KEY | ALT_KEY | UP_KEY | KEY_MODIFIERS')])400    self.assertEqual(expected_entries, definition.entries)401    definition = definitions[4]402    self.assertEqual(403        collections.OrderedDict([('TEST_VAL', 0), ('CODEC_MPEG2', 1)]),404        definition.entries)405  def testParseThrowsOnUnknownDirective(self):406    test_data = """407      // GENERATED_JAVA_UNKNOWN: Value408      enum EnumName {409        VALUE_ONE,410      };411    """.split('\n')412    with self.assertRaises(Exception):413      HeaderParser(test_data).ParseDefinitions()414  def testParseReturnsEmptyListWithoutDirectives(self):415    test_data = """416      enum EnumName {417        VALUE_ONE,418      };419    """.split('\n')420    self.assertEqual([], HeaderParser(test_data).ParseDefinitions())421  def testParseEnumClass(self):422    test_data = """423      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace424      enum class Foo {425        FOO_A,426      };427    """.split('\n')428    definitions = HeaderParser(test_data).ParseDefinitions()429    self.assertEqual(1, len(definitions))430    definition = definitions[0]431    self.assertEqual('Foo', definition.class_name)432    self.assertEqual('test.namespace', definition.enum_package)433    self.assertEqual(collections.OrderedDict([('A', 0)]),434                     definition.entries)435  def testParseEnumClassOneValueSubstringOfAnother(self):436    test_data = """437      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace438      enum class SafeBrowsingStatus {439        kChecking = 0,440        kEnabled = 1,441        kDisabled = 2,442        kDisabledByAdmin = 3,443        kDisabledByExtension = 4,444        kEnabledStandard = 5,445        kEnabledEnhanced = 6,446        // New enum values must go above here.447        kMaxValue = kEnabledEnhanced,448      };449    """.split('\n')450    definitions = HeaderParser(test_data).ParseDefinitions()451    self.assertEqual(1, len(definitions))452    definition = definitions[0]453    self.assertEqual('SafeBrowsingStatus', definition.class_name)454    self.assertEqual('test.namespace', definition.enum_package)455    self.assertEqual(456        collections.OrderedDict([457            ('CHECKING', '0'),458            ('ENABLED', '1'),459            ('DISABLED', '2'),460            ('DISABLED_BY_ADMIN', '3'),461            ('DISABLED_BY_EXTENSION', '4'),462            ('ENABLED_STANDARD', '5'),463            ('ENABLED_ENHANCED', '6'),464            ('MAX_VALUE', 'ENABLED_ENHANCED'),465        ]), definition.entries)466    self.assertEqual(467        collections.OrderedDict([468            ('MAX_VALUE', 'New enum values must go above here.')469        ]), definition.comments)470  def testParseEnumStruct(self):471    test_data = """472      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace473      enum struct Foo {474        FOO_A,475      };476    """.split('\n')477    definitions = HeaderParser(test_data).ParseDefinitions()478    self.assertEqual(1, len(definitions))479    definition = definitions[0]480    self.assertEqual('Foo', definition.class_name)481    self.assertEqual('test.namespace', definition.enum_package)482    self.assertEqual(collections.OrderedDict([('A', 0)]),483                     definition.entries)484  def testParseFixedTypeEnum(self):485    test_data = """486      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace487      enum Foo : int {488        FOO_A,489      };490    """.split('\n')491    definitions = HeaderParser(test_data).ParseDefinitions()492    self.assertEqual(1, len(definitions))493    definition = definitions[0]494    self.assertEqual('Foo', definition.class_name)495    self.assertEqual('test.namespace', definition.enum_package)496    self.assertEqual('int', definition.fixed_type)497    self.assertEqual(collections.OrderedDict([('A', 0)]),498                     definition.entries)499  def testParseFixedTypeEnumClass(self):500    test_data = """501      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace502      enum class Foo: unsigned short {503        FOO_A,504      };505    """.split('\n')506    definitions = HeaderParser(test_data).ParseDefinitions()507    self.assertEqual(1, len(definitions))508    definition = definitions[0]509    self.assertEqual('Foo', definition.class_name)510    self.assertEqual('test.namespace', definition.enum_package)511    self.assertEqual('unsigned short', definition.fixed_type)512    self.assertEqual(collections.OrderedDict([('A', 0)]),513                     definition.entries)514  def testParseUnknownFixedTypeRaises(self):515    test_data = """516      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace517      enum class Foo: foo_type {518        FOO_A,519      };520    """.split('\n')521    with self.assertRaises(Exception):522      HeaderParser(test_data).ParseDefinitions()523  def testParseSimpleMultiLineDirective(self):524    test_data = """525      // GENERATED_JAVA_ENUM_PACKAGE: (526      //   test.namespace)527      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar528      enum Foo {529        FOO_A,530      };531    """.split('\n')532    definitions = HeaderParser(test_data).ParseDefinitions()533    self.assertEqual('test.namespace', definitions[0].enum_package)534    self.assertEqual('Bar', definitions[0].class_name)535  def testParseMultiLineDirective(self):536    test_data = """537      // GENERATED_JAVA_ENUM_PACKAGE: (te538      //   st.name539      //   space)540      enum Foo {541        FOO_A,542      };543    """.split('\n')544    definitions = HeaderParser(test_data).ParseDefinitions()545    self.assertEqual('test.namespace', definitions[0].enum_package)546  def testParseMultiLineDirectiveWithOtherDirective(self):547    test_data = """548      // GENERATED_JAVA_ENUM_PACKAGE: (549      //   test.namespace)550      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: (551      //   Ba552      //   r553      //   )554      enum Foo {555        FOO_A,556      };557    """.split('\n')558    definitions = HeaderParser(test_data).ParseDefinitions()559    self.assertEqual('test.namespace', definitions[0].enum_package)560    self.assertEqual('Bar', definitions[0].class_name)561  def testParseMalformedMultiLineDirectiveWithOtherDirective(self):562    test_data = """563      // GENERATED_JAVA_ENUM_PACKAGE: (564      //   test.name565      //   space566      // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar567      enum Foo {568        FOO_A,569      };570    """.split('\n')571    with self.assertRaises(Exception):572      HeaderParser(test_data).ParseDefinitions()573  def testParseMalformedMultiLineDirective(self):574    test_data = """575      // GENERATED_JAVA_ENUM_PACKAGE: (576      //   test.name577      //   space578      enum Foo {579        FOO_A,580      };581    """.split('\n')582    with self.assertRaises(Exception):583      HeaderParser(test_data).ParseDefinitions()584  def testParseMalformedMultiLineDirectiveShort(self):585    test_data = """586      // GENERATED_JAVA_ENUM_PACKAGE: (587      enum Foo {588        FOO_A,589      };590    """.split('\n')591    with self.assertRaises(Exception):592      HeaderParser(test_data).ParseDefinitions()593  def testParseMalformedMultiLineDirectiveMissingBrackets(self):594    test_data = """595      // GENERATED_JAVA_ENUM_PACKAGE:596      // test.namespace597      enum Foo {598        FOO_A,599      };600    """.split('\n')601    with self.assertRaises(Exception):602      HeaderParser(test_data).ParseDefinitions()603  def testEnumValueAssignmentNoneDefined(self):604    definition = EnumDefinition(original_enum_name='c', enum_package='p')605    definition.AppendEntry('A', None)606    definition.AppendEntry('B', None)607    definition.AppendEntry('C', None)608    definition.Finalize()609    self.assertEqual(collections.OrderedDict([('A', 0),610                                              ('B', 1),611                                              ('C', 2)]),612                     definition.entries)613  def testEnumValueAssignmentAllDefined(self):614    definition = EnumDefinition(original_enum_name='c', enum_package='p')615    definition.AppendEntry('A', '1')616    definition.AppendEntry('B', '2')617    definition.AppendEntry('C', '3')618    definition.Finalize()619    self.assertEqual(collections.OrderedDict([('A', '1'),620                                              ('B', '2'),621                                              ('C', '3')]),622                     definition.entries)623  def testEnumValueAssignmentReferences(self):624    definition = EnumDefinition(original_enum_name='c', enum_package='p')625    definition.AppendEntry('A', None)626    definition.AppendEntry('B', 'A')627    definition.AppendEntry('C', None)628    definition.AppendEntry('D', 'C')629    definition.Finalize()630    self.assertEqual(collections.OrderedDict([('A', 0),631                                              ('B', 0),632                                              ('C', 1),633                                              ('D', 1)]),634                     definition.entries)635  def testEnumValueAssignmentSet(self):636    definition = EnumDefinition(original_enum_name='c', enum_package='p')637    definition.AppendEntry('A', None)638    definition.AppendEntry('B', '2')639    definition.AppendEntry('C', None)640    definition.Finalize()641    self.assertEqual(collections.OrderedDict([('A', 0),642                                              ('B', 2),643                                              ('C', 3)]),644                     definition.entries)645  def testEnumValueAssignmentSetReferences(self):646    definition = EnumDefinition(original_enum_name='c', enum_package='p')647    definition.AppendEntry('A', None)648    definition.AppendEntry('B', 'A')649    definition.AppendEntry('C', 'B')650    definition.AppendEntry('D', None)651    definition.Finalize()652    self.assertEqual(collections.OrderedDict([('A', 0),653                                              ('B', 0),654                                              ('C', 0),655                                              ('D', 1)]),656                     definition.entries)657  def testEnumValueAssignmentRaises(self):658    definition = EnumDefinition(original_enum_name='c', enum_package='p')659    definition.AppendEntry('A', None)660    definition.AppendEntry('B', 'foo')661    definition.AppendEntry('C', None)662    with self.assertRaises(Exception):663      definition.Finalize()664  def testExplicitPrefixStripping(self):665    definition = EnumDefinition(original_enum_name='c', enum_package='p')666    definition.AppendEntry('P_A', None)667    definition.AppendEntry('B', None)668    definition.AppendEntry('P_C', None)669    definition.AppendEntry('P_LAST', 'P_C')670    definition.prefix_to_strip = 'P_'671    definition.Finalize()672    self.assertEqual(collections.OrderedDict([('A', 0),673                                              ('B', 1),674                                              ('C', 2),675                                              ('LAST', 2)]),676                     definition.entries)677  def testImplicitPrefixStripping(self):678    definition = EnumDefinition(original_enum_name='ClassName',679                                enum_package='p')680    definition.AppendEntry('CLASS_NAME_A', None)681    definition.AppendEntry('CLASS_NAME_B', None)682    definition.AppendEntry('CLASS_NAME_C', None)683    definition.AppendEntry('CLASS_NAME_LAST', 'CLASS_NAME_C')684    definition.Finalize()685    self.assertEqual(collections.OrderedDict([('A', 0),686                                              ('B', 1),687                                              ('C', 2),688                                              ('LAST', 2)]),689                     definition.entries)690  def testImplicitPrefixStrippingRequiresAllConstantsToBePrefixed(self):691    definition = EnumDefinition(original_enum_name='Name',692                                enum_package='p')693    definition.AppendEntry('A', None)694    definition.AppendEntry('B', None)695    definition.AppendEntry('NAME_LAST', None)696    definition.Finalize()697    self.assertEqual(['A', 'B', 'NAME_LAST'], list(definition.entries.keys()))698  def testGenerateThrowsOnEmptyInput(self):699    with self.assertRaises(Exception):700      original_do_parse = java_cpp_enum.DoParseHeaderFile701      try:702        java_cpp_enum.DoParseHeaderFile = lambda _: []703        for _ in java_cpp_enum.DoGenerate(['file']):704          pass705      finally:706        java_cpp_enum.DoParseHeaderFile = original_do_parse707if __name__ == '__main__':...java_cpp_enum.py
Source:java_cpp_enum.py  
1#!/usr/bin/env python2#3# Copyright 2014 The Chromium Authors. All rights reserved.4# Use of this source code is governed by a BSD-style license that can be5# found in the LICENSE file.6import collections7from datetime import date8import re9import optparse10import os11from string import Template12import sys13import textwrap14import zipfile15from util import build_utils16from util import java_cpp_utils17# List of C++ types that are compatible with the Java code generated by this18# script.19#20# This script can parse .idl files however, at present it ignores special21# rules such as [cpp_enum_prefix_override="ax_attr"].22ENUM_FIXED_TYPE_ALLOWLIST = [23    'char', 'unsigned char', 'short', 'unsigned short', 'int', 'int8_t',24    'int16_t', 'int32_t', 'uint8_t', 'uint16_t'25]26class EnumDefinition(object):27  def __init__(self, original_enum_name=None, class_name_override=None,28               enum_package=None, entries=None, comments=None, fixed_type=None):29    self.original_enum_name = original_enum_name30    self.class_name_override = class_name_override31    self.enum_package = enum_package32    self.entries = collections.OrderedDict(entries or [])33    self.comments = collections.OrderedDict(comments or [])34    self.prefix_to_strip = None35    self.fixed_type = fixed_type36  def AppendEntry(self, key, value):37    if key in self.entries:38      raise Exception('Multiple definitions of key %s found.' % key)39    self.entries[key] = value40  def AppendEntryComment(self, key, value):41    if key in self.comments:42      raise Exception('Multiple definitions of key %s found.' % key)43    self.comments[key] = value44  @property45  def class_name(self):46    return self.class_name_override or self.original_enum_name47  def Finalize(self):48    self._Validate()49    self._AssignEntryIndices()50    self._StripPrefix()51    self._NormalizeNames()52  def _Validate(self):53    assert self.class_name54    assert self.enum_package55    assert self.entries56    if self.fixed_type and self.fixed_type not in ENUM_FIXED_TYPE_ALLOWLIST:57      raise Exception('Fixed type %s for enum %s not in allowlist.' %58                      (self.fixed_type, self.class_name))59  def _AssignEntryIndices(self):60    # Enums, if given no value, are given the value of the previous enum + 1.61    if not all(self.entries.values()):62      prev_enum_value = -163      for key, value in self.entries.items():64        if not value:65          self.entries[key] = prev_enum_value + 166        elif value in self.entries:67          self.entries[key] = self.entries[value]68        else:69          try:70            self.entries[key] = int(value)71          except ValueError:72            raise Exception('Could not interpret integer from enum value "%s" '73                            'for key %s.' % (value, key))74        prev_enum_value = self.entries[key]75  def _StripPrefix(self):76    prefix_to_strip = self.prefix_to_strip77    if not prefix_to_strip:78      shout_case = self.original_enum_name79      shout_case = re.sub('(?!^)([A-Z]+)', r'_\1', shout_case).upper()80      shout_case += '_'81      prefixes = [shout_case, self.original_enum_name,82                  'k' + self.original_enum_name]83      for prefix in prefixes:84        if all([w.startswith(prefix) for w in self.entries.keys()]):85          prefix_to_strip = prefix86          break87      else:88        prefix_to_strip = ''89    def StripEntries(entries):90      ret = collections.OrderedDict()91      for k, v in entries.items():92        stripped_key = k.replace(prefix_to_strip, '', 1)93        if isinstance(v, str):94          stripped_value = v.replace(prefix_to_strip, '')95        else:96          stripped_value = v97        ret[stripped_key] = stripped_value98      return ret99    self.entries = StripEntries(self.entries)100    self.comments = StripEntries(self.comments)101  def _NormalizeNames(self):102    self.entries = _TransformKeys(self.entries, java_cpp_utils.KCamelToShouty)103    self.comments = _TransformKeys(self.comments, java_cpp_utils.KCamelToShouty)104def _TransformKeys(d, func):105  """Normalize keys in |d| and update references to old keys in |d| values."""106  keys_map = {k: func(k) for k in d}107  ret = collections.OrderedDict()108  for k, v in d.items():109    # Need to transform values as well when the entry value was explicitly set110    # (since it could contain references to other enum entry values).111    if isinstance(v, str):112      # First check if a full replacement is available. This avoids issues when113      # one key is a substring of another.114      if v in d:115        v = keys_map[v]116      else:117        for old_key, new_key in keys_map.items():118          v = v.replace(old_key, new_key)119    ret[keys_map[k]] = v120  return ret121class DirectiveSet(object):122  class_name_override_key = 'CLASS_NAME_OVERRIDE'123  enum_package_key = 'ENUM_PACKAGE'124  prefix_to_strip_key = 'PREFIX_TO_STRIP'125  known_keys = [class_name_override_key, enum_package_key, prefix_to_strip_key]126  def __init__(self):127    self._directives = {}128  def Update(self, key, value):129    if key not in DirectiveSet.known_keys:130      raise Exception("Unknown directive: " + key)131    self._directives[key] = value132  @property133  def empty(self):134    return len(self._directives) == 0135  def UpdateDefinition(self, definition):136    definition.class_name_override = self._directives.get(137        DirectiveSet.class_name_override_key, '')138    definition.enum_package = self._directives.get(139        DirectiveSet.enum_package_key)140    definition.prefix_to_strip = self._directives.get(141        DirectiveSet.prefix_to_strip_key)142class HeaderParser(object):143  single_line_comment_re = re.compile(r'\s*//\s*([^\n]*)')144  multi_line_comment_start_re = re.compile(r'\s*/\*')145  enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,\n]+))?,?')146  enum_end_re = re.compile(r'^\s*}\s*;\.*$')147  generator_error_re = re.compile(r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*$')148  generator_directive_re = re.compile(149      r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$')150  multi_line_generator_directive_start_re = re.compile(151      r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*\(([\.\w]*)$')152  multi_line_directive_continuation_re = re.compile(r'^\s*//\s+([\.\w]+)$')153  multi_line_directive_end_re = re.compile(r'^\s*//\s+([\.\w]*)\)$')154  optional_class_or_struct_re = r'(class|struct)?'155  enum_name_re = r'(\w+)'156  optional_fixed_type_re = r'(\:\s*(\w+\s*\w+?))?'157  enum_start_re = re.compile(r'^\s*(?:\[cpp.*\])?\s*enum\s+' +158      optional_class_or_struct_re + '\s*' + enum_name_re + '\s*' +159      optional_fixed_type_re + '\s*{\s*')160  enum_single_line_re = re.compile(161      r'^\s*(?:\[cpp.*\])?\s*enum.*{(?P<enum_entries>.*)}.*$')162  def __init__(self, lines, path=''):163    self._lines = lines164    self._path = path165    self._enum_definitions = []166    self._in_enum = False167    self._current_definition = None168    self._current_comments = []169    self._generator_directives = DirectiveSet()170    self._multi_line_generator_directive = None171    self._current_enum_entry = ''172  def _ApplyGeneratorDirectives(self):173    self._generator_directives.UpdateDefinition(self._current_definition)174    self._generator_directives = DirectiveSet()175  def ParseDefinitions(self):176    for line in self._lines:177      self._ParseLine(line)178    return self._enum_definitions179  def _ParseLine(self, line):180    if self._multi_line_generator_directive:181      self._ParseMultiLineDirectiveLine(line)182    elif not self._in_enum:183      self._ParseRegularLine(line)184    else:185      self._ParseEnumLine(line)186  def _ParseEnumLine(self, line):187    if HeaderParser.multi_line_comment_start_re.match(line):188      raise Exception('Multi-line comments in enums are not supported in ' +189                      self._path)190    enum_comment = HeaderParser.single_line_comment_re.match(line)191    if enum_comment:192      comment = enum_comment.groups()[0]193      if comment:194        self._current_comments.append(comment)195    elif HeaderParser.enum_end_re.match(line):196      self._FinalizeCurrentEnumDefinition()197    else:198      self._AddToCurrentEnumEntry(line)199      if ',' in line:200        self._ParseCurrentEnumEntry()201  def _ParseSingleLineEnum(self, line):202    for entry in line.split(','):203      self._AddToCurrentEnumEntry(entry)204      self._ParseCurrentEnumEntry()205    self._FinalizeCurrentEnumDefinition()206  def _ParseCurrentEnumEntry(self):207    if not self._current_enum_entry:208      return209    enum_entry = HeaderParser.enum_line_re.match(self._current_enum_entry)210    if not enum_entry:211      raise Exception('Unexpected error while attempting to parse %s as enum '212                      'entry.' % self._current_enum_entry)213    enum_key = enum_entry.groups()[0]214    enum_value = enum_entry.groups()[2]215    self._current_definition.AppendEntry(enum_key, enum_value)216    if self._current_comments:217      self._current_definition.AppendEntryComment(218          enum_key, ' '.join(self._current_comments))219      self._current_comments = []220    self._current_enum_entry = ''221  def _AddToCurrentEnumEntry(self, line):222    self._current_enum_entry += ' ' + line.strip()223  def _FinalizeCurrentEnumDefinition(self):224    if self._current_enum_entry:225      self._ParseCurrentEnumEntry()226    self._ApplyGeneratorDirectives()227    self._current_definition.Finalize()228    self._enum_definitions.append(self._current_definition)229    self._current_definition = None230    self._in_enum = False231  def _ParseMultiLineDirectiveLine(self, line):232    multi_line_directive_continuation = (233        HeaderParser.multi_line_directive_continuation_re.match(line))234    multi_line_directive_end = (235        HeaderParser.multi_line_directive_end_re.match(line))236    if multi_line_directive_continuation:237      value_cont = multi_line_directive_continuation.groups()[0]238      self._multi_line_generator_directive[1].append(value_cont)239    elif multi_line_directive_end:240      directive_name = self._multi_line_generator_directive[0]241      directive_value = "".join(self._multi_line_generator_directive[1])242      directive_value += multi_line_directive_end.groups()[0]243      self._multi_line_generator_directive = None244      self._generator_directives.Update(directive_name, directive_value)245    else:246      raise Exception('Malformed multi-line directive declaration in ' +247                      self._path)248  def _ParseRegularLine(self, line):249    enum_start = HeaderParser.enum_start_re.match(line)250    generator_directive_error = HeaderParser.generator_error_re.match(line)251    generator_directive = HeaderParser.generator_directive_re.match(line)252    multi_line_generator_directive_start = (253        HeaderParser.multi_line_generator_directive_start_re.match(line))254    single_line_enum = HeaderParser.enum_single_line_re.match(line)255    if generator_directive_error:256      raise Exception('Malformed directive declaration in ' + self._path +257                      '. Use () for multi-line directives. E.g.\n' +258                      '// GENERATED_JAVA_ENUM_PACKAGE: (\n' +259                      '//   foo.package)')260    elif generator_directive:261      directive_name = generator_directive.groups()[0]262      directive_value = generator_directive.groups()[1]263      self._generator_directives.Update(directive_name, directive_value)264    elif multi_line_generator_directive_start:265      directive_name = multi_line_generator_directive_start.groups()[0]266      directive_value = multi_line_generator_directive_start.groups()[1]267      self._multi_line_generator_directive = (directive_name, [directive_value])268    elif enum_start or single_line_enum:269      if self._generator_directives.empty:270        return271      self._current_definition = EnumDefinition(272          original_enum_name=enum_start.groups()[1],273          fixed_type=enum_start.groups()[3])274      self._in_enum = True275      if single_line_enum:276        self._ParseSingleLineEnum(single_line_enum.group('enum_entries'))277def DoGenerate(source_paths):278  for source_path in source_paths:279    enum_definitions = DoParseHeaderFile(source_path)280    if not enum_definitions:281      raise Exception('No enums found in %s\n'282                      'Did you forget prefixing enums with '283                      '"// GENERATED_JAVA_ENUM_PACKAGE: foo"?' %284                      source_path)285    for enum_definition in enum_definitions:286      output_path = java_cpp_utils.GetJavaFilePath(enum_definition.enum_package,287                                                   enum_definition.class_name)288      output = GenerateOutput(source_path, enum_definition)289      yield output_path, output290def DoParseHeaderFile(path):291  with open(path) as f:292    return HeaderParser(f.readlines(), path).ParseDefinitions()293def GenerateOutput(source_path, enum_definition):294  template = Template("""295// Copyright ${YEAR} The Chromium Authors. All rights reserved.296// Use of this source code is governed by a BSD-style license that can be297// found in the LICENSE file.298// This file is autogenerated by299//     ${SCRIPT_NAME}300// From301//     ${SOURCE_PATH}302package ${PACKAGE};303import androidx.annotation.IntDef;304import java.lang.annotation.Retention;305import java.lang.annotation.RetentionPolicy;306@IntDef({307${INT_DEF}308})309@Retention(RetentionPolicy.SOURCE)310public @interface ${CLASS_NAME} {311${ENUM_ENTRIES}312}313""")314  enum_template = Template('  int ${NAME} = ${VALUE};')315  enum_entries_string = []316  enum_names = []317  for enum_name, enum_value in enum_definition.entries.items():318    values = {319        'NAME': enum_name,320        'VALUE': enum_value,321    }322    enum_comments = enum_definition.comments.get(enum_name)323    if enum_comments:324      enum_comments_indent = '   * '325      comments_line_wrapper = textwrap.TextWrapper(326          initial_indent=enum_comments_indent,327          subsequent_indent=enum_comments_indent,328          width=100)329      enum_entries_string.append('  /**')330      enum_entries_string.append('\n'.join(331          comments_line_wrapper.wrap(enum_comments)))332      enum_entries_string.append('   */')333    enum_entries_string.append(enum_template.substitute(values))334    if enum_name != "NUM_ENTRIES":335      enum_names.append(enum_definition.class_name + '.' + enum_name)336  enum_entries_string = '\n'.join(enum_entries_string)337  enum_names_indent = ' ' * 4338  wrapper = textwrap.TextWrapper(initial_indent = enum_names_indent,339                                 subsequent_indent = enum_names_indent,340                                 width = 100)341  enum_names_string = '\n'.join(wrapper.wrap(', '.join(enum_names)))342  values = {343      'CLASS_NAME': enum_definition.class_name,344      'ENUM_ENTRIES': enum_entries_string,345      'PACKAGE': enum_definition.enum_package,346      'INT_DEF': enum_names_string,347      'SCRIPT_NAME': java_cpp_utils.GetScriptName(),348      'SOURCE_PATH': source_path,349      'YEAR': str(date.today().year)350  }351  return template.substitute(values)352def DoMain(argv):353  usage = 'usage: %prog [options] [output_dir] input_file(s)...'354  parser = optparse.OptionParser(usage=usage)355  parser.add_option('--srcjar',356                    help='When specified, a .srcjar at the given path is '357                    'created instead of individual .java files.')358  options, args = parser.parse_args(argv)359  if not args:360    parser.error('Need to specify at least one input file')361  input_paths = args362  with build_utils.AtomicOutput(options.srcjar) as f:363    with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as srcjar:364      for output_path, data in DoGenerate(input_paths):365        build_utils.AddToZipHermetic(srcjar, output_path, data=data)366if __name__ == '__main__':...parser.py
Source:parser.py  
1#!/usr/bin/env python32#3# Copyright (C) 2017 The Android Open Source Project4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9#      http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16#17# A parser for enum types defined in HIDL.18# This script can parse HIDL files and generate a parse tree.19# To use, import and call parse("path/to/file.hal")20# It will return a Python dictionary with three keys:21#  - header: an instance of Header22#  - enums: a dictionary of EnumDecl objects by name23#  - structs: a dictionary of StructDecl objects by name24# It requires 'ply' (Python Lex/Yacc).25from __future__ import print_function26import ply27tokens = ('package', 'import', 'enum', 'struct',28    'COLON', 'IDENTIFIER', 'COMMENT', 'NUMBER', 'HEX', 'OR', 'EQUALS',29    'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'DOT', 'SEMICOLON', 'VERSION',30    'COMMA', 'SHIFT', 'LESSTHAN', 'GREATERTHAN')31t_COLON = r':'32t_NUMBER = r'[0-9]+'33t_HEX = r'0x[0-9A-Fa-f]+'34t_OR = r'\|'35t_EQUALS = r'='36t_LPAREN = r'\('37t_RPAREN = r'\)'38t_SHIFT = r'<<'39t_LESSTHAN = r'<'40t_GREATERTHAN = r'>'41def t_COMMENT(t):42    r'(/\*(.|\n)*?\*/)|(//.*)'43    pass44t_LBRACE = r'{'45t_RBRACE = r'}'46t_DOT = r'\.'47t_SEMICOLON = r';'48t_VERSION = r'@[0-9].[0-9]'49t_COMMA = r','50t_ignore = ' \n\t'51def t_IDENTIFIER(t):52    r'[a-zA-Z_][a-zA-Z_0-9]*'53    if t.value == 'package':54        t.type = 'package'55    elif t.value == 'import':56        t.type = 'import'57    elif t.value == 'enum':58        t.type = 'enum'59    elif t.value == 'struct':60        t.type = 'struct'61    return t62def t_error(t):63    t.type = t.value[0]64    t.value = t.value[0]65    t.lexer.skip(1)66    return t67import ply.lex as lex68lexer = lex.lex()69class Typename(object):70    pass71class SimpleTypename(Typename):72    def __init__(self, name):73        self.name = name74    def __str__(self):75        return self.name76class GenericTypename(Typename):77    def __init__(self, name, arg):78        self.name = name79        self.arg = arg80    def __str__(self):81        return '%s<%s>' % (self.name, self.arg)82class EnumHeader(object):83    def __init__(self, name, base):84        self.name = name85        self.base = base86    def __str__(self):87        return '%s%s' % (self.name, ' %s' % self.base if self.base else '')88class StructHeader(object):89    def __init__(self, name):90        self.name = name91    def __str__(self):92        return 'struct %s' % self.name93class EnumDecl(object):94    def __init__(self, header, cases):95        self.header = header96        self.cases = cases97        self.fillInValues()98    def fillInValues(self):99        # if no cases, we're done100        if len(self.cases) < 1: return101        # then, if case 0 has no value, set it to 0102        if self.cases[0].value is None:103            self.cases[0].value = EnumValueConstant("0")104        # then for all other cases...105        for i in range(1,len(self.cases)):106            # ...if there's no value107            if self.cases[i].value is None:108                # set to previous case + 1109                self.cases[i].value = EnumValueSuccessor(110                    EnumValueLocalRef(self.cases[i-1].name))111    def __str__(self):112        return '%s {\n%s\n}' % (self.header,113            '\n'.join(str(x) for x in self.cases))114    def __repr__(self):115        return self.__str__()116class StructDecl(object):117    def __init__(self, header, items):118        self.header = header119        self.items = items120    def __str__(self):121        return '%s {\n%s\n}' % (self.header,122            '\n'.join(str(x) for x in self.items))123    def __repr__(self):124        return self.__str__()125class StructElement(object):126    pass127class StructElementIVar(StructElement):128    def __init__(self, typename, name):129        self.typename = typename130        self.name = name131    def __str__(self):132        return '%s %s' % (self.typename, self.name)133class StructElementStruct(StructElement):134    def __init__(self, struct):135        self.name = struct.header.name136        self.struct = struct137    def __str__(self):138        return self.struct.__str__()139class EnumCase(object):140    def __init__(self, name, value):141        self.name = name142        self.value = value143    def __str__(self):144        return '%s = %s' % (self.name, self.value)145class PackageID(object):146    def __init__(self, name, version):147        self.name = name148        self.version = version149    def __str__(self):150        return '%s%s' % (self.name, self.version)151class Package(object):152    def __init__(self, package):153        self.package = package154    def __str__(self):155        return 'package %s' % self.package156class Import(object):157    def __init__(self, package):158        self.package = package159    def __str__(self):160        return 'import %s' % self.package161class Header(object):162    def __init__(self, package, imports):163        self.package = package164        self.imports = imports165    def __str__(self):166        return str(self.package) + "\n" + \167            '\n'.join(str(x) for x in self.imports)168class EnumValue(object):169    def resolve(self, enum, document):170        pass171class EnumValueConstant(EnumValue):172    def __init__(self, value):173        self.value = value174    def __str__(self):175        return self.value176    def resolve(self, enum, document):177        if self.value.startswith("0x"):178            return int(self.value, 16)179        else:180            return int(self.value, 10)181class EnumValueSuccessor(EnumValue):182    def __init__(self, value):183        self.value = value184    def __str__(self):185        return '%s + 1' % self.value186    def resolve(self, enum, document):187        return self.value.resolve(enum, document) + 1188class EnumValueLocalRef(EnumValue):189    def __init__(self, ref):190        self.ref = ref191    def __str__(self):192        return self.ref193    def resolve(self, enum, document):194        for case in enum.cases:195            if case.name == self.ref: return case.value.resolve(enum, document)196class EnumValueLShift(EnumValue):197    def __init__(self, base, offset):198        self.base = base199        self.offset = offset200    def __str__(self):201        return '%s << %s' % (self.base, self.offset)202    def resolve(self, enum, document):203        base = self.base.resolve(enum, document)204        offset = self.offset.resolve(enum, document)205        return base << offset206class EnumValueOr(EnumValue):207    def __init__(self, param1, param2):208        self.param1 = param1209        self.param2 = param2210    def __str__(self):211        return '%s | %s' % (self.param1, self.param2)212    def resolve(self, enum, document):213        param1 = self.param1.resolve(enum, document)214        param2 = self.param2.resolve(enum, document)215        return param1 | param2216class EnumValueExternRef(EnumValue):217    def __init__(self, where, ref):218        self.where = where219        self.ref = ref220    def __str__(self):221        return '%s:%s' % (self.where, self.ref)222    def resolve(self, enum, document):223        enum = document['enums'][self.where]224        return EnumValueLocalRef(self.ref).resolve(enum, document)225# Error rule for syntax errors226def p_error(p):227    print("Syntax error in input: %s" % p)228    try:229        while True:230            print(p.lexer.next().value, end=' ')231    except:232        pass233def p_document(t):234    'document : header type_decls'235    enums = {}236    structs = {}237    for enum in t[2]:238        if not isinstance(enum, EnumDecl): continue239        enums[enum.header.name] = enum240    for struct in t[2]:241        if not isinstance(struct, StructDecl): continue242        structs[struct.header.name] = struct243    t[0] = {'header' : t[1], 'enums' : enums, 'structs' : structs}244def p_type_decls_1(t):245    'type_decls : type_decl'246    t[0] = [t[1]]247def p_type_decls_2(t):248    'type_decls : type_decls type_decl'249    t[0] = t[1] + [t[2]]250def p_type_decl_e(t):251    'type_decl : enum_decl'252    t[0] = t[1]253def p_type_decl_s(t):254    'type_decl : struct_decl'255    t[0] = t[1]256def p_enum_cases_1(t):257    'enum_cases : enum_case'258    t[0] = [t[1]]259def p_enum_cases_2(t):260    'enum_cases : enum_cases COMMA enum_case'261    t[0] = t[1] + [t[3]]262def p_struct_elements_1(t):263    'struct_elements : struct_element'264    t[0] = [t[1]]265def p_struct_elements_2(t):266    'struct_elements : struct_elements struct_element'267    t[0] = t[1] + [t[2]]268def p_enum_base_1(t):269    'enum_base : VERSION COLON COLON IDENTIFIER'270    t[0] = '%s::%s' % (t[1], t[4])271def p_enum_base_2(t):272    'enum_base : IDENTIFIER'273    t[0] = t[1]274def p_struct_header(t):275    'struct_header : struct IDENTIFIER'276    t[0] = StructHeader(t[2])277def p_enum_header_1(t):278    'enum_header : enum IDENTIFIER'279    t[0] = EnumHeader(t[2], None)280def p_enum_header_2(t):281    'enum_header : enum IDENTIFIER COLON enum_base'282    t[0] = EnumHeader(t[2], t[4])283def p_struct_decl(t):284    'struct_decl : struct_header LBRACE struct_elements RBRACE SEMICOLON'285    t[0] = StructDecl(t[1], t[3])286def p_enum_decl_1(t):287    'enum_decl : enum_header LBRACE enum_cases RBRACE SEMICOLON'288    t[0] = EnumDecl(t[1], t[3])289def p_enum_decl_2(t):290    'enum_decl : enum_header LBRACE enum_cases COMMA RBRACE SEMICOLON'291    t[0] = EnumDecl(t[1], t[3])292def p_enum_value_1(t):293    '''enum_value : NUMBER294                  | HEX'''295    t[0] = EnumValueConstant(t[1])296def p_enum_value_2(t):297    'enum_value : enum_value SHIFT NUMBER'298    t[0] = EnumValueLShift(t[1], EnumValueConstant(t[3]))299def p_enum_value_3(t):300    'enum_value : enum_value OR enum_value'301    t[0] = EnumValueOr(t[1], t[3])302def p_enum_value_4(t):303    'enum_value : LPAREN enum_value RPAREN'304    t[0] = t[2]305def p_enum_value_5(t):306    'enum_value : IDENTIFIER COLON IDENTIFIER'307    t[0] = EnumValueExternRef(t[1],t[3])308def p_enum_value_6(t):309    'enum_value : IDENTIFIER'310    t[0] = EnumValueLocalRef(t[1])311def p_typename_v(t):312    'typename : IDENTIFIER'313    t[0] = SimpleTypename(t[1])314def p_typename_g(t):315    'typename : IDENTIFIER LESSTHAN IDENTIFIER GREATERTHAN'316    t[0] = GenericTypename(t[1], t[3])317def p_struct_element_ivar(t):318    'struct_element : typename IDENTIFIER SEMICOLON'319    t[0] = StructElementIVar(t[1], t[2])320def p_struct_element_struct(t):321    'struct_element : struct_decl'322    t[0] = StructElementStruct(t[1])323def p_enum_case_v(t):324    'enum_case : IDENTIFIER EQUALS enum_value'325    t[0] = EnumCase(t[1], t[3])326def p_enum_case_b(t):327    'enum_case : IDENTIFIER'328    t[0] = EnumCase(t[1], None)329def p_header_1(t):330    'header : package_decl'331    t[0] = Header(t[1], [])332def p_header_2(t):333    'header : package_decl import_decls'334    t[0] = Header(t[1], t[2])335def p_import_decls_1(t):336    'import_decls : import_decl'337    t[0] = [t[1]]338def p_import_decls_2(t):339    'import_decls : import_decls import_decl'340    t[0] = t[1] + [t[2]]341def p_package_decl(t):342    'package_decl : package package_ID SEMICOLON'343    t[0] = Package(t[2])344def p_import_decl(t):345    'import_decl : import package_ID SEMICOLON'346    t[0] = Import(t[2])347def p_package_ID(t):348    'package_ID : dotted_identifier VERSION'349    t[0] = PackageID(t[1], t[2])350def p_dotted_identifier_1(t):351    'dotted_identifier : IDENTIFIER'352    t[0] = t[1]353def p_dotted_identifier_2(t):354    'dotted_identifier : dotted_identifier DOT IDENTIFIER'355    t[0] = t[1] + '.' + t[3]356class SilentLogger(object):357    def warning(*args):358        pass359import ply.yacc as yacc360parser = yacc.yacc(debug=False, write_tables=False, errorlog=SilentLogger())361import sys362def parse(filename):...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
