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.
5 """Node classes for the AST for a Mojo IDL file."""
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.
13 class NodeBase(object):
14 """Base class for nodes in the AST."""
16 def __init__(self, filename=None, lineno=None):
17 self.filename = filename
20 def __eq__(self, other):
21 return type(self) == type(other)
23 # Make != the inverse of ==. (Subclasses shouldn't have to override this.)
24 def __ne__(self, other):
25 return not self == other
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.)"""
34 def __init__(self, item_or_items=None, **kwargs):
35 super(NodeListBase, self).__init__(**kwargs)
37 if item_or_items is None:
39 elif isinstance(item_or_items, list):
40 for item in item_or_items:
41 assert isinstance(item, self._list_item_type)
44 assert isinstance(item_or_items, self._list_item_type)
45 self.Append(item_or_items)
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.)
51 return self.items.__iter__()
53 def __eq__(self, other):
54 return super(NodeListBase, self).__eq__(other) and \
55 self.items == other.items
57 # Implement this so that on failure, we get slightly more sensible output.
59 return self.__class__.__name__ + "([" + \
60 ", ".join([repr(elem) for elem in self.items]) + "])"
62 def Insert(self, item):
63 """Inserts item at the front of the list."""
65 assert isinstance(item, self._list_item_type)
66 self.items.insert(0, item)
67 self._UpdateFilenameAndLineno()
69 def Append(self, item):
70 """Appends item to the end of the list."""
72 assert isinstance(item, self._list_item_type)
73 self.items.append(item)
74 self._UpdateFilenameAndLineno()
76 def _UpdateFilenameAndLineno(self):
78 self.filename = self.items[0].filename
79 self.lineno = self.items[0].lineno
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."""
87 def __init__(self, name, **kwargs):
88 assert isinstance(name, str)
89 NodeBase.__init__(self, **kwargs)
93 ################################################################################
96 class Attribute(NodeBase):
97 """Represents an attribute."""
99 def __init__(self, key, value, **kwargs):
100 assert isinstance(key, str)
101 super(Attribute, self).__init__(**kwargs)
105 def __eq__(self, other):
106 return super(Attribute, self).__eq__(other) and \
107 self.key == other.key and \
108 self.value == other.value
111 class AttributeList(NodeListBase):
112 """Represents a list attributes."""
114 _list_item_type = Attribute
117 class Const(Definition):
118 """Represents a const definition."""
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
130 def __eq__(self, other):
131 return super(Const, self).__eq__(other) and \
132 self.typename == other.typename and \
133 self.value == other.value
136 class Enum(Definition):
137 """Represents an enum definition."""
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
144 def __eq__(self, other):
145 return super(Enum, self).__eq__(other) and \
146 self.enum_value_list == other.enum_value_list
149 class EnumValue(Definition):
150 """Represents a definition of an enum value."""
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)
159 def __eq__(self, other):
160 return super(EnumValue, self).__eq__(other) and \
161 self.value == other.value
164 class EnumValueList(NodeListBase):
165 """Represents a list of enum value definitions (i.e., the "body" of an enum
168 _list_item_type = EnumValue
171 class Import(NodeBase):
172 """Represents an import statement."""
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
179 def __eq__(self, other):
180 return super(Import, self).__eq__(other) and \
181 self.import_filename == other.import_filename
184 class ImportList(NodeListBase):
185 """Represents a list (i.e., sequence) of import statements."""
187 _list_item_type = Import
190 class Interface(Definition):
191 """Represents an interface definition."""
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
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
206 class Method(Definition):
207 """Represents a method definition."""
209 def __init__(self, name, ordinal, parameter_list, response_parameter_list,
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
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
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."""
231 _list_item_type = (Const, Enum, Method)
234 class Module(NodeBase):
235 """Represents a module statement."""
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)
243 self.attribute_list = attribute_list
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
251 class Mojom(NodeBase):
252 """Represents an entire .mojom file. (This is the root node.)"""
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)
260 self.import_list = import_list
261 self.definition_list = definition_list
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
270 return "%s(%r, %r, %r)" % (self.__class__.__name__, self.module,
271 self.import_list, self.definition_list)
274 class Ordinal(NodeBase):
275 """Represents an ordinal value labeling, e.g., a struct field."""
277 def __init__(self, value, **kwargs):
278 assert isinstance(value, int)
279 super(Ordinal, self).__init__(**kwargs)
282 def __eq__(self, other):
283 return super(Ordinal, self).__eq__(other) and \
284 self.value == other.value
287 class Parameter(NodeBase):
288 """Represents a method request or response parameter."""
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)
296 self.ordinal = ordinal
297 self.typename = typename
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
306 class ParameterList(NodeListBase):
307 """Represents a list of (method request or response) parameters."""
309 _list_item_type = Parameter
312 class Struct(Definition):
313 """Represents a struct definition."""
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
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
328 class StructField(Definition):
329 """Represents a struct field definition."""
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
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
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."""
354 _list_item_type = (Const, Enum, StructField)