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 13class 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. 29class 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 82class 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, mojom_name, **kwargs): 88 assert isinstance(mojom_name, str) 89 NodeBase.__init__(self, **kwargs) 90 self.mojom_name = mojom_name 91 92 93################################################################################ 94 95 96class 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 111class AttributeList(NodeListBase): 112 """Represents a list attributes.""" 113 114 _list_item_type = Attribute 115 116 117class Const(Definition): 118 """Represents a const definition.""" 119 120 def __init__(self, mojom_name, attribute_list, typename, value, **kwargs): 121 assert attribute_list is None or isinstance(attribute_list, AttributeList) 122 # The typename is currently passed through as a string. 123 assert isinstance(typename, str) 124 # The value is either a literal (currently passed through as a string) or a 125 # "wrapped identifier". 126 assert isinstance(value, str) or isinstance(value, tuple) 127 super(Const, self).__init__(mojom_name, **kwargs) 128 self.attribute_list = attribute_list 129 self.typename = typename 130 self.value = value 131 132 def __eq__(self, other): 133 return super(Const, self).__eq__(other) and \ 134 self.attribute_list == other.attribute_list and \ 135 self.typename == other.typename and \ 136 self.value == other.value 137 138 139class Enum(Definition): 140 """Represents an enum definition.""" 141 142 def __init__(self, mojom_name, attribute_list, enum_value_list, **kwargs): 143 assert attribute_list is None or isinstance(attribute_list, AttributeList) 144 assert enum_value_list is None or isinstance(enum_value_list, EnumValueList) 145 super(Enum, self).__init__(mojom_name, **kwargs) 146 self.attribute_list = attribute_list 147 self.enum_value_list = enum_value_list 148 149 def __eq__(self, other): 150 return super(Enum, self).__eq__(other) and \ 151 self.attribute_list == other.attribute_list and \ 152 self.enum_value_list == other.enum_value_list 153 154 155class EnumValue(Definition): 156 """Represents a definition of an enum value.""" 157 158 def __init__(self, mojom_name, attribute_list, value, **kwargs): 159 # The optional value is either an int (which is current a string) or a 160 # "wrapped identifier". 161 assert attribute_list is None or isinstance(attribute_list, AttributeList) 162 assert value is None or isinstance(value, (str, tuple)) 163 super(EnumValue, self).__init__(mojom_name, **kwargs) 164 self.attribute_list = attribute_list 165 self.value = value 166 167 def __eq__(self, other): 168 return super(EnumValue, self).__eq__(other) and \ 169 self.attribute_list == other.attribute_list and \ 170 self.value == other.value 171 172 173class EnumValueList(NodeListBase): 174 """Represents a list of enum value definitions (i.e., the "body" of an enum 175 definition).""" 176 177 _list_item_type = EnumValue 178 179 180class Import(NodeBase): 181 """Represents an import statement.""" 182 183 def __init__(self, attribute_list, import_filename, **kwargs): 184 assert attribute_list is None or isinstance(attribute_list, AttributeList) 185 assert isinstance(import_filename, str) 186 super(Import, self).__init__(**kwargs) 187 self.attribute_list = attribute_list 188 self.import_filename = import_filename 189 190 def __eq__(self, other): 191 return super(Import, self).__eq__(other) and \ 192 self.attribute_list == other.attribute_list and \ 193 self.import_filename == other.import_filename 194 195 196class ImportList(NodeListBase): 197 """Represents a list (i.e., sequence) of import statements.""" 198 199 _list_item_type = Import 200 201 202class Interface(Definition): 203 """Represents an interface definition.""" 204 205 def __init__(self, mojom_name, attribute_list, body, **kwargs): 206 assert attribute_list is None or isinstance(attribute_list, AttributeList) 207 assert isinstance(body, InterfaceBody) 208 super(Interface, self).__init__(mojom_name, **kwargs) 209 self.attribute_list = attribute_list 210 self.body = body 211 212 def __eq__(self, other): 213 return super(Interface, self).__eq__(other) and \ 214 self.attribute_list == other.attribute_list and \ 215 self.body == other.body 216 217 218class Method(Definition): 219 """Represents a method definition.""" 220 221 def __init__(self, mojom_name, attribute_list, ordinal, parameter_list, 222 response_parameter_list, **kwargs): 223 assert attribute_list is None or isinstance(attribute_list, AttributeList) 224 assert ordinal is None or isinstance(ordinal, Ordinal) 225 assert isinstance(parameter_list, ParameterList) 226 assert response_parameter_list is None or \ 227 isinstance(response_parameter_list, ParameterList) 228 super(Method, self).__init__(mojom_name, **kwargs) 229 self.attribute_list = attribute_list 230 self.ordinal = ordinal 231 self.parameter_list = parameter_list 232 self.response_parameter_list = response_parameter_list 233 234 def __eq__(self, other): 235 return super(Method, self).__eq__(other) and \ 236 self.attribute_list == other.attribute_list and \ 237 self.ordinal == other.ordinal and \ 238 self.parameter_list == other.parameter_list and \ 239 self.response_parameter_list == other.response_parameter_list 240 241 242# This needs to be declared after |Method|. 243class InterfaceBody(NodeListBase): 244 """Represents the body of (i.e., list of definitions inside) an interface.""" 245 246 _list_item_type = (Const, Enum, Method) 247 248 249class Module(NodeBase): 250 """Represents a module statement.""" 251 252 def __init__(self, mojom_namespace, attribute_list, **kwargs): 253 # |mojom_namespace| is either none or a "wrapped identifier". 254 assert mojom_namespace is None or isinstance(mojom_namespace, tuple) 255 assert attribute_list is None or isinstance(attribute_list, AttributeList) 256 super(Module, self).__init__(**kwargs) 257 self.mojom_namespace = mojom_namespace 258 self.attribute_list = attribute_list 259 260 def __eq__(self, other): 261 return super(Module, self).__eq__(other) and \ 262 self.mojom_namespace == other.mojom_namespace and \ 263 self.attribute_list == other.attribute_list 264 265 266class Mojom(NodeBase): 267 """Represents an entire .mojom file. (This is the root node.)""" 268 269 def __init__(self, module, import_list, definition_list, **kwargs): 270 assert module is None or isinstance(module, Module) 271 assert isinstance(import_list, ImportList) 272 assert isinstance(definition_list, list) 273 super(Mojom, self).__init__(**kwargs) 274 self.module = module 275 self.import_list = import_list 276 self.definition_list = definition_list 277 278 def __eq__(self, other): 279 return super(Mojom, self).__eq__(other) and \ 280 self.module == other.module and \ 281 self.import_list == other.import_list and \ 282 self.definition_list == other.definition_list 283 284 def __repr__(self): 285 return "%s(%r, %r, %r)" % (self.__class__.__name__, self.module, 286 self.import_list, self.definition_list) 287 288 289class Ordinal(NodeBase): 290 """Represents an ordinal value labeling, e.g., a struct field.""" 291 292 def __init__(self, value, **kwargs): 293 assert isinstance(value, int) 294 super(Ordinal, self).__init__(**kwargs) 295 self.value = value 296 297 def __eq__(self, other): 298 return super(Ordinal, self).__eq__(other) and \ 299 self.value == other.value 300 301 302class Parameter(NodeBase): 303 """Represents a method request or response parameter.""" 304 305 def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs): 306 assert isinstance(mojom_name, str) 307 assert attribute_list is None or isinstance(attribute_list, AttributeList) 308 assert ordinal is None or isinstance(ordinal, Ordinal) 309 assert isinstance(typename, str) 310 super(Parameter, self).__init__(**kwargs) 311 self.mojom_name = mojom_name 312 self.attribute_list = attribute_list 313 self.ordinal = ordinal 314 self.typename = typename 315 316 def __eq__(self, other): 317 return super(Parameter, self).__eq__(other) and \ 318 self.mojom_name == other.mojom_name and \ 319 self.attribute_list == other.attribute_list and \ 320 self.ordinal == other.ordinal and \ 321 self.typename == other.typename 322 323 324class ParameterList(NodeListBase): 325 """Represents a list of (method request or response) parameters.""" 326 327 _list_item_type = Parameter 328 329 330class Struct(Definition): 331 """Represents a struct definition.""" 332 333 def __init__(self, mojom_name, attribute_list, body, **kwargs): 334 assert attribute_list is None or isinstance(attribute_list, AttributeList) 335 assert isinstance(body, StructBody) or body is None 336 super(Struct, self).__init__(mojom_name, **kwargs) 337 self.attribute_list = attribute_list 338 self.body = body 339 340 def __eq__(self, other): 341 return super(Struct, self).__eq__(other) and \ 342 self.attribute_list == other.attribute_list and \ 343 self.body == other.body 344 345 346class StructField(Definition): 347 """Represents a struct field definition.""" 348 349 def __init__(self, mojom_name, attribute_list, ordinal, typename, 350 default_value, **kwargs): 351 assert isinstance(mojom_name, str) 352 assert attribute_list is None or isinstance(attribute_list, AttributeList) 353 assert ordinal is None or isinstance(ordinal, Ordinal) 354 assert isinstance(typename, str) 355 # The optional default value is currently either a value as a string or a 356 # "wrapped identifier". 357 assert default_value is None or isinstance(default_value, (str, tuple)) 358 super(StructField, self).__init__(mojom_name, **kwargs) 359 self.attribute_list = attribute_list 360 self.ordinal = ordinal 361 self.typename = typename 362 self.default_value = default_value 363 364 def __eq__(self, other): 365 return super(StructField, self).__eq__(other) and \ 366 self.attribute_list == other.attribute_list and \ 367 self.ordinal == other.ordinal and \ 368 self.typename == other.typename and \ 369 self.default_value == other.default_value 370 371 372# This needs to be declared after |StructField|. 373class StructBody(NodeListBase): 374 """Represents the body of (i.e., list of definitions inside) a struct.""" 375 376 _list_item_type = (Const, Enum, StructField) 377 378 379class Union(Definition): 380 """Represents a union definition.""" 381 382 def __init__(self, mojom_name, attribute_list, body, **kwargs): 383 assert attribute_list is None or isinstance(attribute_list, AttributeList) 384 assert isinstance(body, UnionBody) 385 super(Union, self).__init__(mojom_name, **kwargs) 386 self.attribute_list = attribute_list 387 self.body = body 388 389 def __eq__(self, other): 390 return super(Union, self).__eq__(other) and \ 391 self.attribute_list == other.attribute_list and \ 392 self.body == other.body 393 394 395class UnionField(Definition): 396 397 def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs): 398 assert isinstance(mojom_name, str) 399 assert attribute_list is None or isinstance(attribute_list, AttributeList) 400 assert ordinal is None or isinstance(ordinal, Ordinal) 401 assert isinstance(typename, str) 402 super(UnionField, self).__init__(mojom_name, **kwargs) 403 self.attribute_list = attribute_list 404 self.ordinal = ordinal 405 self.typename = typename 406 407 def __eq__(self, other): 408 return super(UnionField, self).__eq__(other) and \ 409 self.attribute_list == other.attribute_list and \ 410 self.ordinal == other.ordinal and \ 411 self.typename == other.typename 412 413 414class UnionBody(NodeListBase): 415 416 _list_item_type = UnionField 417