Home | History | Annotate | Download | only in parse
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Node classes for the AST for a Mojo IDL file."""
      6 
      7 # Note: For convenience of testing, you probably want to define __eq__() methods
      8 # for all node types; it's okay to be slightly lax (e.g., not compare filename
      9 # and lineno). You may also define __repr__() to help with analyzing test
     10 # failures, especially for more complex types.
     11 
     12 
     13 class NodeBase(object):
     14   """Base class for nodes in the AST."""
     15 
     16   def __init__(self, filename=None, lineno=None):
     17     self.filename = filename
     18     self.lineno = lineno
     19 
     20   def __eq__(self, other):
     21     return type(self) == type(other)
     22 
     23   # Make != the inverse of ==. (Subclasses shouldn't have to override this.)
     24   def __ne__(self, other):
     25     return not self == other
     26 
     27 
     28 # TODO(vtl): Some of this is complicated enough that it should be tested.
     29 class NodeListBase(NodeBase):
     30   """Represents a list of other nodes, all having the same type. (This is meant
     31   to be subclassed, with subclasses defining _list_item_type to be the class (or
     32   classes, in a tuple) of the members of the list.)"""
     33 
     34   def __init__(self, item_or_items=None, **kwargs):
     35     super(NodeListBase, self).__init__(**kwargs)
     36     self.items = []
     37     if item_or_items is None:
     38       pass
     39     elif isinstance(item_or_items, list):
     40       for item in item_or_items:
     41         assert isinstance(item, self._list_item_type)
     42         self.Append(item)
     43     else:
     44       assert isinstance(item_or_items, self._list_item_type)
     45       self.Append(item_or_items)
     46 
     47   # Support iteration. For everything else, users should just access |items|
     48   # directly. (We intentionally do NOT supply |__len__()| or |__nonzero__()|, so
     49   # |bool(NodeListBase())| is true.)
     50   def __iter__(self):
     51     return self.items.__iter__()
     52 
     53   def __eq__(self, other):
     54     return super(NodeListBase, self).__eq__(other) and \
     55            self.items == other.items
     56 
     57   # Implement this so that on failure, we get slightly more sensible output.
     58   def __repr__(self):
     59     return self.__class__.__name__ + "([" + \
     60            ", ".join([repr(elem) for elem in self.items]) + "])"
     61 
     62   def Insert(self, item):
     63     """Inserts item at the front of the list."""
     64 
     65     assert isinstance(item, self._list_item_type)
     66     self.items.insert(0, item)
     67     self._UpdateFilenameAndLineno()
     68 
     69   def Append(self, item):
     70     """Appends item to the end of the list."""
     71 
     72     assert isinstance(item, self._list_item_type)
     73     self.items.append(item)
     74     self._UpdateFilenameAndLineno()
     75 
     76   def _UpdateFilenameAndLineno(self):
     77     if self.items:
     78       self.filename = self.items[0].filename
     79       self.lineno = self.items[0].lineno
     80 
     81 
     82 class Definition(NodeBase):
     83   """Represents a definition of anything that has a global name (e.g., enums,
     84   enum values, consts, structs, struct fields, interfaces). (This does not
     85   include parameter definitions.) This class is meant to be subclassed."""
     86 
     87   def __init__(self, name, **kwargs):
     88     assert isinstance(name, str)
     89     NodeBase.__init__(self, **kwargs)
     90     self.name = name
     91 
     92 
     93 ################################################################################
     94 
     95 
     96 class Attribute(NodeBase):
     97   """Represents an attribute."""
     98 
     99   def __init__(self, key, value, **kwargs):
    100     assert isinstance(key, str)
    101     super(Attribute, self).__init__(**kwargs)
    102     self.key = key
    103     self.value = value
    104 
    105   def __eq__(self, other):
    106     return super(Attribute, self).__eq__(other) and \
    107            self.key == other.key and \
    108            self.value == other.value
    109 
    110 
    111 class AttributeList(NodeListBase):
    112   """Represents a list attributes."""
    113 
    114   _list_item_type = Attribute
    115 
    116 
    117 class Const(Definition):
    118   """Represents a const definition."""
    119 
    120   def __init__(self, name, typename, value, **kwargs):
    121     # The typename is currently passed through as a string.
    122     assert isinstance(typename, str)
    123     # The value is either a literal (currently passed through as a string) or a
    124     # "wrapped identifier".
    125     assert isinstance(value, str) or isinstance(value, tuple)
    126     super(Const, self).__init__(name, **kwargs)
    127     self.typename = typename
    128     self.value = value
    129 
    130   def __eq__(self, other):
    131     return super(Const, self).__eq__(other) and \
    132            self.typename == other.typename and \
    133            self.value == other.value
    134 
    135 
    136 class Enum(Definition):
    137   """Represents an enum definition."""
    138 
    139   def __init__(self, name, enum_value_list, **kwargs):
    140     assert isinstance(enum_value_list, EnumValueList)
    141     super(Enum, self).__init__(name, **kwargs)
    142     self.enum_value_list = enum_value_list
    143 
    144   def __eq__(self, other):
    145     return super(Enum, self).__eq__(other) and \
    146            self.enum_value_list == other.enum_value_list
    147 
    148 
    149 class EnumValue(Definition):
    150   """Represents a definition of an enum value."""
    151 
    152   def __init__(self, name, value, **kwargs):
    153     # The optional value is either an int (which is current a string) or a
    154     # "wrapped identifier".
    155     assert value is None or isinstance(value, (str, tuple))
    156     super(EnumValue, self).__init__(name, **kwargs)
    157     self.value = value
    158 
    159   def __eq__(self, other):
    160     return super(EnumValue, self).__eq__(other) and \
    161            self.value == other.value
    162 
    163 
    164 class EnumValueList(NodeListBase):
    165   """Represents a list of enum value definitions (i.e., the "body" of an enum
    166   definition)."""
    167 
    168   _list_item_type = EnumValue
    169 
    170 
    171 class Import(NodeBase):
    172   """Represents an import statement."""
    173 
    174   def __init__(self, import_filename, **kwargs):
    175     assert isinstance(import_filename, str)
    176     super(Import, self).__init__(**kwargs)
    177     self.import_filename = import_filename
    178 
    179   def __eq__(self, other):
    180     return super(Import, self).__eq__(other) and \
    181            self.import_filename == other.import_filename
    182 
    183 
    184 class ImportList(NodeListBase):
    185   """Represents a list (i.e., sequence) of import statements."""
    186 
    187   _list_item_type = Import
    188 
    189 
    190 class Interface(Definition):
    191   """Represents an interface definition."""
    192 
    193   def __init__(self, name, attribute_list, body, **kwargs):
    194     assert attribute_list is None or isinstance(attribute_list, AttributeList)
    195     assert isinstance(body, InterfaceBody)
    196     super(Interface, self).__init__(name, **kwargs)
    197     self.attribute_list = attribute_list
    198     self.body = body
    199 
    200   def __eq__(self, other):
    201     return super(Interface, self).__eq__(other) and \
    202            self.attribute_list == other.attribute_list and \
    203            self.body == other.body
    204 
    205 
    206 class Method(Definition):
    207   """Represents a method definition."""
    208 
    209   def __init__(self, name, ordinal, parameter_list, response_parameter_list,
    210                **kwargs):
    211     assert ordinal is None or isinstance(ordinal, Ordinal)
    212     assert isinstance(parameter_list, ParameterList)
    213     assert response_parameter_list is None or \
    214            isinstance(response_parameter_list, ParameterList)
    215     super(Method, self).__init__(name, **kwargs)
    216     self.ordinal = ordinal
    217     self.parameter_list = parameter_list
    218     self.response_parameter_list = response_parameter_list
    219 
    220   def __eq__(self, other):
    221     return super(Method, self).__eq__(other) and \
    222            self.ordinal == other.ordinal and \
    223            self.parameter_list == other.parameter_list and \
    224            self.response_parameter_list == other.response_parameter_list
    225 
    226 
    227 # This needs to be declared after |Method|.
    228 class InterfaceBody(NodeListBase):
    229   """Represents the body of (i.e., list of definitions inside) an interface."""
    230 
    231   _list_item_type = (Const, Enum, Method)
    232 
    233 
    234 class Module(NodeBase):
    235   """Represents a module statement."""
    236 
    237   def __init__(self, name, attribute_list, **kwargs):
    238     # |name| is either none or a "wrapped identifier".
    239     assert name is None or isinstance(name, tuple)
    240     assert attribute_list is None or isinstance(attribute_list, AttributeList)
    241     super(Module, self).__init__(**kwargs)
    242     self.name = name
    243     self.attribute_list = attribute_list
    244 
    245   def __eq__(self, other):
    246     return super(Module, self).__eq__(other) and \
    247            self.name == other.name and \
    248            self.attribute_list == other.attribute_list
    249 
    250 
    251 class Mojom(NodeBase):
    252   """Represents an entire .mojom file. (This is the root node."""
    253 
    254   def __init__(self, module, import_list, definition_list, **kwargs):
    255     assert module is None or isinstance(module, Module)
    256     assert isinstance(import_list, ImportList)
    257     assert isinstance(definition_list, list)
    258     super(Mojom, self).__init__(**kwargs)
    259     self.module = module
    260     self.import_list = import_list
    261     self.definition_list = definition_list
    262 
    263   def __eq__(self, other):
    264     return super(Mojom, self).__eq__(other) and \
    265            self.module == other.module and \
    266            self.import_list == other.import_list and \
    267            self.definition_list == other.definition_list
    268 
    269   def __repr__(self):
    270     return "%s(%r, %r, %r)" % (self.__class__.__name__, self.module,
    271                                self.import_list, self.definition_list)
    272 
    273 
    274 class Ordinal(NodeBase):
    275   """Represents an ordinal value labeling, e.g., a struct field."""
    276 
    277   def __init__(self, value, **kwargs):
    278     assert isinstance(value, int)
    279     super(Ordinal, self).__init__(**kwargs)
    280     self.value = value
    281 
    282   def __eq__(self, other):
    283     return super(Ordinal, self).__eq__(other) and \
    284            self.value == other.value
    285 
    286 
    287 class Parameter(NodeBase):
    288   """Represents a method request or response parameter."""
    289 
    290   def __init__(self, name, ordinal, typename, **kwargs):
    291     assert isinstance(name, str)
    292     assert ordinal is None or isinstance(ordinal, Ordinal)
    293     assert isinstance(typename, str)
    294     super(Parameter, self).__init__(**kwargs)
    295     self.name = name
    296     self.ordinal = ordinal
    297     self.typename = typename
    298 
    299   def __eq__(self, other):
    300     return super(Parameter, self).__eq__(other) and \
    301            self.name == other.name and \
    302            self.ordinal == other.ordinal and \
    303            self.typename == other.typename
    304 
    305 
    306 class ParameterList(NodeListBase):
    307   """Represents a list of (method request or response) parameters."""
    308 
    309   _list_item_type = Parameter
    310 
    311 
    312 class Struct(Definition):
    313   """Represents a struct definition."""
    314 
    315   def __init__(self, name, attribute_list, body, **kwargs):
    316     assert attribute_list is None or isinstance(attribute_list, AttributeList)
    317     assert isinstance(body, StructBody)
    318     super(Struct, self).__init__(name, **kwargs)
    319     self.attribute_list = attribute_list
    320     self.body = body
    321 
    322   def __eq__(self, other):
    323     return super(Struct, self).__eq__(other) and \
    324            self.attribute_list == other.attribute_list and \
    325            self.body == other.body
    326 
    327 
    328 class StructField(Definition):
    329   """Represents a struct field definition."""
    330 
    331   def __init__(self, name, ordinal, typename, default_value, **kwargs):
    332     assert isinstance(name, str)
    333     assert ordinal is None or isinstance(ordinal, Ordinal)
    334     assert isinstance(typename, str)
    335     # The optional default value is currently either a value as a string or a
    336     # "wrapped identifier".
    337     assert default_value is None or isinstance(default_value, (str, tuple))
    338     super(StructField, self).__init__(name, **kwargs)
    339     self.ordinal = ordinal
    340     self.typename = typename
    341     self.default_value = default_value
    342 
    343   def __eq__(self, other):
    344     return super(StructField, self).__eq__(other) and \
    345            self.ordinal == other.ordinal and \
    346            self.typename == other.typename and \
    347            self.default_value == other.default_value
    348 
    349 
    350 # This needs to be declared after |StructField|.
    351 class StructBody(NodeListBase):
    352   """Represents the body of (i.e., list of definitions inside) a struct."""
    353 
    354   _list_item_type = (Const, Enum, StructField)
    355