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