OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Node classes for the AST for a Mojo IDL file.""" | 5 """Node classes for the AST for a Mojo IDL file.""" |
6 | 6 |
7 # Note: For convenience of testing, you probably want to define __eq__() methods | 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 | 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 | 9 # and lineno). You may also define __repr__() to help with analyzing test |
10 # failures, especially for more complex types. | 10 # failures, especially for more complex types. |
11 | 11 |
12 | 12 |
13 class NodeBase(object): | 13 class NodeBase(object): |
14 """Base class for nodes in the AST.""" | 14 """Base class for nodes in the AST.""" |
15 | 15 |
16 def __init__(self, filename=None, lineno=None): | 16 def __init__(self, filename=None, lineno=None): |
17 self.filename = filename | 17 self.filename = filename |
18 self.lineno = lineno | 18 self.lineno = lineno |
19 | 19 |
20 def __eq__(self, other): | 20 def __eq__(self, other): |
21 return type(self) == type(other) | 21 return type(self) == type(other) |
22 | 22 |
23 | 23 |
24 # TODO(vtl): Some of this is complicated enough that it should be tested. | 24 # TODO(vtl): Some of this is complicated enough that it should be tested. |
25 class NodeListBase(NodeBase): | 25 class NodeListBase(NodeBase): |
26 """Represents a list of other nodes, all having the same type. (This is meant | 26 """Represents a list of other nodes, all having the same type. (This is meant |
27 to be subclassed, with subclasses defining _list_item_type to be the class of | 27 to be subclassed, with subclasses defining _list_item_type to be the class (or |
28 the members of the list; _list_item_type should also be a NodeBase.)""" | 28 classes, in a tuple) of the members of the list.)""" |
29 | 29 |
30 def __init__(self, item_or_items=None, **kwargs): | 30 def __init__(self, item_or_items=None, **kwargs): |
31 assert issubclass(self._list_item_type, NodeBase) | |
32 super(NodeListBase, self).__init__(**kwargs) | 31 super(NodeListBase, self).__init__(**kwargs) |
| 32 self.items = [] |
33 if item_or_items is None: | 33 if item_or_items is None: |
34 self.elements = [] | 34 pass |
| 35 self.items = [] |
35 elif isinstance(item_or_items, list): | 36 elif isinstance(item_or_items, list): |
36 # TODO(vtl): Possibly we should assert that each element of the list is a | 37 for item in item_or_items: |
37 # |_list_item_type|. | 38 assert isinstance(item, self._list_item_type) |
38 self.elements = list(item_or_items) | 39 self.Append(item) |
39 else: | 40 else: |
40 assert isinstance(item_or_items, self._list_item_type) | 41 assert isinstance(item_or_items, self._list_item_type) |
41 self.elements = [item_or_items] | 42 self.Append(item_or_items) |
42 self._UpdateFilenameAndLineno() | |
43 | 43 |
44 # Support iteration. For everything else, users should just access |elements| | 44 # Support iteration. For everything else, users should just access |items| |
45 # directly. (We intentionally do NOT supply |__len__()| or |__nonzero__()|, so | 45 # directly. (We intentionally do NOT supply |__len__()| or |__nonzero__()|, so |
46 # |bool(NodeListBase())| is true.) | 46 # |bool(NodeListBase())| is true.) |
47 def __iter__(self): | 47 def __iter__(self): |
48 return self.elements.__iter__() | 48 return self.items.__iter__() |
49 | 49 |
50 def __eq__(self, other): | 50 def __eq__(self, other): |
51 return super(NodeListBase, self).__eq__(other) and \ | 51 return super(NodeListBase, self).__eq__(other) and \ |
52 len(self.elements) == len(other.elements) and \ | 52 len(self.items) == len(other.items) and \ |
53 all(self.elements[i] == other.elements[i] \ | 53 all(self.items[i] == other.items[i] for i in xrange(len(self.items))) |
54 for i in xrange(len(self.elements))) | |
55 | 54 |
56 # Implement this so that on failure, we get slightly more sensible output. | 55 # Implement this so that on failure, we get slightly more sensible output. |
57 def __repr__(self): | 56 def __repr__(self): |
58 return self.__class__.__name__ + "([" + \ | 57 return self.__class__.__name__ + "([" + \ |
59 ", ".join([repr(elem) for elem in self.elements]) + "])" | 58 ", ".join([repr(elem) for elem in self.items]) + "])" |
| 59 |
| 60 def Insert(self, item): |
| 61 """Inserts item at the front of the list.""" |
| 62 |
| 63 assert isinstance(item, self._list_item_type) |
| 64 self.items.insert(0, item) |
| 65 self._UpdateFilenameAndLineno() |
60 | 66 |
61 def Append(self, item): | 67 def Append(self, item): |
| 68 """Appends item to the end of the list.""" |
| 69 |
62 assert isinstance(item, self._list_item_type) | 70 assert isinstance(item, self._list_item_type) |
63 self.elements.append(item) | 71 self.items.append(item) |
64 self._UpdateFilenameAndLineno() | 72 self._UpdateFilenameAndLineno() |
65 | 73 |
66 def _UpdateFilenameAndLineno(self): | 74 def _UpdateFilenameAndLineno(self): |
67 if self.elements: | 75 if self.items: |
68 self.filename = self.elements[0].filename | 76 self.filename = self.items[0].filename |
69 self.lineno = self.elements[0].lineno | 77 self.lineno = self.items[0].lineno |
70 | 78 |
71 | 79 |
72 class Definition(NodeBase): | 80 class Definition(NodeBase): |
73 """Represents a definition of anything that has a global name (e.g., enums, | 81 """Represents a definition of anything that has a global name (e.g., enums, |
74 enum values, consts, structs, struct fields, interfaces). (This does not | 82 enum values, consts, structs, struct fields, interfaces). (This does not |
75 include parameter definitions.) This class is meant to be subclassed.""" | 83 include parameter definitions.) This class is meant to be subclassed.""" |
76 | 84 |
77 def __init__(self, name, **kwargs): | 85 def __init__(self, name, **kwargs): |
78 assert isinstance(name, str) | 86 assert isinstance(name, str) |
79 NodeBase.__init__(self, **kwargs) | 87 NodeBase.__init__(self, **kwargs) |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 self.ordinal == other.ordinal and \ | 256 self.ordinal == other.ordinal and \ |
249 self.typename == other.typename | 257 self.typename == other.typename |
250 | 258 |
251 | 259 |
252 class ParameterList(NodeListBase): | 260 class ParameterList(NodeListBase): |
253 """Represents a list of (method request or response) parameters.""" | 261 """Represents a list of (method request or response) parameters.""" |
254 | 262 |
255 _list_item_type = Parameter | 263 _list_item_type = Parameter |
256 | 264 |
257 | 265 |
| 266 class Struct(Definition): |
| 267 """Represents a struct definition.""" |
| 268 |
| 269 def __init__(self, name, attribute_list, body, **kwargs): |
| 270 assert attribute_list is None or isinstance(attribute_list, AttributeList) |
| 271 assert isinstance(body, StructBody) |
| 272 super(Struct, self).__init__(name, **kwargs) |
| 273 self.attribute_list = attribute_list |
| 274 self.body = body |
| 275 |
| 276 def __eq__(self, other): |
| 277 return super(Struct, self).__eq__(other) and \ |
| 278 self.attribute_list == other.attribute_list and \ |
| 279 self.body == other.body |
| 280 |
| 281 |
258 class StructField(Definition): | 282 class StructField(Definition): |
259 """Represents a struct field definition.""" | 283 """Represents a struct field definition.""" |
260 | 284 |
261 def __init__(self, name, ordinal, typename, default_value, **kwargs): | 285 def __init__(self, name, ordinal, typename, default_value, **kwargs): |
262 assert isinstance(name, str) | 286 assert isinstance(name, str) |
263 assert ordinal is None or isinstance(ordinal, Ordinal) | 287 assert ordinal is None or isinstance(ordinal, Ordinal) |
264 assert isinstance(typename, str) | 288 assert isinstance(typename, str) |
265 # The optional default value is currently either a value as a string or a | 289 # The optional default value is currently either a value as a string or a |
266 # "wrapped identifier". | 290 # "wrapped identifier". |
267 assert default_value is None or isinstance(default_value, (str, tuple)) | 291 assert default_value is None or isinstance(default_value, (str, tuple)) |
268 super(StructField, self).__init__(name, **kwargs) | 292 super(StructField, self).__init__(name, **kwargs) |
269 self.ordinal = ordinal | 293 self.ordinal = ordinal |
270 self.typename = typename | 294 self.typename = typename |
271 self.default_value = default_value | 295 self.default_value = default_value |
272 | 296 |
273 def __eq__(self, other): | 297 def __eq__(self, other): |
274 return super(StructField, self).__eq__(other) and \ | 298 return super(StructField, self).__eq__(other) and \ |
275 self.ordinal == other.ordinal and \ | 299 self.ordinal == other.ordinal and \ |
276 self.typename == other.typename and \ | 300 self.typename == other.typename and \ |
277 self.default_value == other.default_value | 301 self.default_value == other.default_value |
| 302 |
| 303 |
| 304 # This needs to be declared after |StructField|. |
| 305 class StructBody(NodeListBase): |
| 306 """Represents the body of (i.e., list of definitions inside) a struct.""" |
| 307 |
| 308 _list_item_type = (Const, Enum, StructField) |
OLD | NEW |