| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 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 import mojom | |
| 6 import copy | |
| 7 | |
| 8 # mojom_data provides a mechanism to turn mojom Modules to dictionaries and | |
| 9 # back again. This can be used to persist a mojom Module created progromatically | |
| 10 # or to read a dictionary from code or a file. | |
| 11 # Example: | |
| 12 # test_dict = { | |
| 13 # 'name': 'test', | |
| 14 # 'namespace': 'testspace', | |
| 15 # 'structs': [{ | |
| 16 # 'name': 'teststruct', | |
| 17 # 'fields': [ | |
| 18 # {'name': 'testfield1', 'kind': 'i32'}, | |
| 19 # {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}], | |
| 20 # 'interfaces': [{ | |
| 21 # 'name': 'Server', | |
| 22 # 'methods': [{ | |
| 23 # 'name': 'Foo', | |
| 24 # 'parameters': [{ | |
| 25 # 'name': 'foo', 'kind': 'i32'}, | |
| 26 # {'name': 'bar', 'kind': 'a:x:teststruct'}], | |
| 27 # 'ordinal': 42}]}] | |
| 28 # } | |
| 29 # test_module = mojom_data.ModuleFromData(test_dict) | |
| 30 | |
| 31 # Used to create a subclass of str that supports sorting by index, to make | |
| 32 # pretty printing maintain the order. | |
| 33 def istr(index, string): | |
| 34 class IndexedString(str): | |
| 35 def __lt__(self, other): | |
| 36 return self.__index__ < other.__index__ | |
| 37 | |
| 38 istr = IndexedString(string) | |
| 39 istr.__index__ = index | |
| 40 return istr | |
| 41 | |
| 42 def LookupKind(kinds, spec, scope): | |
| 43 """Tries to find which Kind a spec refers to, given the scope in which its | |
| 44 referenced. Starts checking from the narrowest scope to most general. For | |
| 45 example, given a struct field like | |
| 46 Foo.Bar x; | |
| 47 Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner | |
| 48 type 'Bar' in the struct 'Foo' in the current namespace. | |
| 49 | |
| 50 |scope| is a tuple that looks like (namespace, struct/interface), referring | |
| 51 to the location where the type is referenced.""" | |
| 52 if spec.startswith('x:'): | |
| 53 name = spec[2:] | |
| 54 for i in xrange(len(scope), -1, -1): | |
| 55 test_spec = 'x:' | |
| 56 if i > 0: | |
| 57 test_spec += '.'.join(scope[:i]) + '.' | |
| 58 test_spec += name | |
| 59 kind = kinds.get(test_spec) | |
| 60 if kind: | |
| 61 return kind | |
| 62 | |
| 63 return kinds.get(spec) | |
| 64 | |
| 65 def LookupConstant(constants, name, scope): | |
| 66 """Like LookupKind, but for constants.""" | |
| 67 for i in xrange(len(scope), -1, -1): | |
| 68 if i > 0: | |
| 69 test_spec = '.'.join(scope[:i]) + '.' | |
| 70 test_spec += name | |
| 71 constant = constants.get(test_spec) | |
| 72 if constant: | |
| 73 return constant | |
| 74 | |
| 75 return constants.get(name) | |
| 76 | |
| 77 def KindToData(kind): | |
| 78 return kind.spec | |
| 79 | |
| 80 def KindFromData(kinds, data, scope): | |
| 81 kind = LookupKind(kinds, data, scope) | |
| 82 if kind: | |
| 83 return kind | |
| 84 if data.startswith('a:'): | |
| 85 kind = mojom.Array() | |
| 86 kind.kind = KindFromData(kinds, data[2:], scope) | |
| 87 else: | |
| 88 kind = mojom.Kind() | |
| 89 kind.spec = data | |
| 90 kinds[data] = kind | |
| 91 return kind | |
| 92 | |
| 93 def KindFromImport(original_kind, imported_from): | |
| 94 """Used with 'import module' - clones the kind imported from the | |
| 95 given module's namespace. Only used with Structs and Enums.""" | |
| 96 kind = copy.deepcopy(original_kind) | |
| 97 kind.imported_from = imported_from | |
| 98 return kind | |
| 99 | |
| 100 def ImportFromData(module, data): | |
| 101 import_module = data['module'] | |
| 102 | |
| 103 import_item = {} | |
| 104 import_item['module_name'] = import_module.name | |
| 105 import_item['namespace'] = import_module.namespace | |
| 106 import_item['module'] = import_module | |
| 107 | |
| 108 # Copy the struct kinds from our imports into the current module. | |
| 109 for kind in import_module.kinds.itervalues(): | |
| 110 if (isinstance(kind, (mojom.Struct, mojom.Enum)) and | |
| 111 kind.imported_from is None): | |
| 112 kind = KindFromImport(kind, import_item) | |
| 113 module.kinds[kind.spec] = kind | |
| 114 # Ditto for constants. | |
| 115 for constant in import_module.constants.itervalues(): | |
| 116 if constant.imported_from is None: | |
| 117 constant = copy.deepcopy(constant) | |
| 118 constant.imported_from = import_item | |
| 119 module.constants[constant.GetSpec()] = constant | |
| 120 | |
| 121 return import_item | |
| 122 | |
| 123 def StructToData(struct): | |
| 124 return { | |
| 125 istr(0, 'name'): struct.name, | |
| 126 istr(1, 'fields'): map(FieldToData, struct.fields) | |
| 127 } | |
| 128 | |
| 129 def StructFromData(module, data): | |
| 130 struct = mojom.Struct() | |
| 131 struct.name = data['name'] | |
| 132 struct.spec = 'x:' + module.namespace + '.' + struct.name | |
| 133 module.kinds[struct.spec] = struct | |
| 134 struct.enums = map(lambda enum: | |
| 135 EnumFromData(module, enum, struct), data['enums']) | |
| 136 struct.fields = map(lambda field: | |
| 137 FieldFromData(module, field, struct), data['fields']) | |
| 138 return struct | |
| 139 | |
| 140 def FieldToData(field): | |
| 141 data = { | |
| 142 istr(0, 'name'): field.name, | |
| 143 istr(1, 'kind'): KindToData(field.kind) | |
| 144 } | |
| 145 if field.ordinal != None: | |
| 146 data[istr(2, 'ordinal')] = field.ordinal | |
| 147 if field.default != None: | |
| 148 data[istr(3, 'default')] = field.default | |
| 149 return data | |
| 150 | |
| 151 def FixupExpression(module, value, scope): | |
| 152 if isinstance(value, (tuple, list)): | |
| 153 for i in xrange(len(value)): | |
| 154 if isinstance(value, tuple): | |
| 155 FixupExpression(module, value[i], scope) | |
| 156 else: | |
| 157 value[i] = FixupExpression(module, value[i], scope) | |
| 158 elif value: | |
| 159 constant = LookupConstant(module.constants, value, scope) | |
| 160 if constant: | |
| 161 return constant | |
| 162 return value | |
| 163 | |
| 164 def FieldFromData(module, data, struct): | |
| 165 field = mojom.Field() | |
| 166 field.name = data['name'] | |
| 167 field.kind = KindFromData( | |
| 168 module.kinds, data['kind'], (module.namespace, struct.name)) | |
| 169 field.ordinal = data.get('ordinal') | |
| 170 field.default = FixupExpression( | |
| 171 module, data.get('default'), (module.namespace, struct.name)) | |
| 172 return field | |
| 173 | |
| 174 def ParameterToData(parameter): | |
| 175 data = { | |
| 176 istr(0, 'name'): parameter.name, | |
| 177 istr(1, 'kind'): parameter.kind.spec | |
| 178 } | |
| 179 if parameter.ordinal != None: | |
| 180 data[istr(2, 'ordinal')] = parameter.ordinal | |
| 181 if parameter.default != None: | |
| 182 data[istr(3, 'default')] = parameter.default | |
| 183 return data | |
| 184 | |
| 185 def ParameterFromData(module, data, interface): | |
| 186 parameter = mojom.Parameter() | |
| 187 parameter.name = data['name'] | |
| 188 parameter.kind = KindFromData( | |
| 189 module.kinds, data['kind'], (module.namespace, interface.name)) | |
| 190 parameter.ordinal = data.get('ordinal') | |
| 191 parameter.default = data.get('default') | |
| 192 return parameter | |
| 193 | |
| 194 def MethodToData(method): | |
| 195 data = { | |
| 196 istr(0, 'name'): method.name, | |
| 197 istr(1, 'parameters'): map(ParameterToData, method.parameters) | |
| 198 } | |
| 199 if method.ordinal != None: | |
| 200 data[istr(2, 'ordinal')] = method.ordinal | |
| 201 if method.response_parameters != None: | |
| 202 data[istr(3, 'response_parameters')] = map( | |
| 203 ParameterToData, method.response_parameters) | |
| 204 return data | |
| 205 | |
| 206 def MethodFromData(module, data, interface): | |
| 207 method = mojom.Method() | |
| 208 method.name = data['name'] | |
| 209 method.ordinal = data.get('ordinal') | |
| 210 method.default = data.get('default') | |
| 211 method.parameters = map(lambda parameter: | |
| 212 ParameterFromData(module, parameter, interface), data['parameters']) | |
| 213 if data.has_key('response_parameters'): | |
| 214 method.response_parameters = map( | |
| 215 lambda parameter: ParameterFromData(module, parameter, interface), | |
| 216 data['response_parameters']) | |
| 217 return method | |
| 218 | |
| 219 def InterfaceToData(interface): | |
| 220 return { | |
| 221 istr(0, 'name'): interface.name, | |
| 222 istr(1, 'peer'): interface.peer, | |
| 223 istr(2, 'methods'): map(MethodToData, interface.methods) | |
| 224 } | |
| 225 | |
| 226 def InterfaceFromData(module, data): | |
| 227 interface = mojom.Interface() | |
| 228 interface.name = data['name'] | |
| 229 interface.spec = 'x:' + module.namespace + '.' + interface.name | |
| 230 interface.peer = data['peer'] if data.has_key('peer') else None | |
| 231 module.kinds[interface.spec] = interface | |
| 232 interface.enums = map(lambda enum: | |
| 233 EnumFromData(module, enum, interface), data['enums']) | |
| 234 interface.methods = map(lambda method: | |
| 235 MethodFromData(module, method, interface), data['methods']) | |
| 236 return interface | |
| 237 | |
| 238 def EnumFieldFromData(module, enum, data, parent_kind): | |
| 239 field = mojom.EnumField() | |
| 240 field.name = data['name'] | |
| 241 if parent_kind: | |
| 242 field.value = FixupExpression( | |
| 243 module, data['value'], (module.namespace, parent_kind.name)) | |
| 244 else: | |
| 245 field.value = FixupExpression( | |
| 246 module, data['value'], (module.namespace, )) | |
| 247 constant = mojom.Constant(module, enum, field) | |
| 248 module.constants[constant.GetSpec()] = constant | |
| 249 return field | |
| 250 | |
| 251 def EnumFromData(module, data, parent_kind): | |
| 252 enum = mojom.Enum() | |
| 253 enum.name = data['name'] | |
| 254 name = enum.name | |
| 255 if parent_kind: | |
| 256 name = parent_kind.name + '.' + name | |
| 257 enum.spec = 'x:%s.%s' % (module.namespace, name) | |
| 258 enum.parent_kind = parent_kind | |
| 259 | |
| 260 enum.fields = map( | |
| 261 lambda field: EnumFieldFromData(module, enum, field, parent_kind), | |
| 262 data['fields']) | |
| 263 module.kinds[enum.spec] = enum | |
| 264 return enum | |
| 265 | |
| 266 def ModuleToData(module): | |
| 267 return { | |
| 268 istr(0, 'name'): module.name, | |
| 269 istr(1, 'namespace'): module.namespace, | |
| 270 istr(2, 'structs'): map(StructToData, module.structs), | |
| 271 istr(3, 'interfaces'): map(InterfaceToData, module.interfaces) | |
| 272 } | |
| 273 | |
| 274 def ModuleFromData(data): | |
| 275 module = mojom.Module() | |
| 276 module.kinds = {} | |
| 277 for kind in mojom.PRIMITIVES: | |
| 278 module.kinds[kind.spec] = kind | |
| 279 | |
| 280 module.constants = {} | |
| 281 | |
| 282 module.name = data['name'] | |
| 283 module.namespace = data['namespace'] | |
| 284 # Imports must come first, because they add to module.kinds which is used | |
| 285 # by by the others. | |
| 286 module.imports = map( | |
| 287 lambda import_data: ImportFromData(module, import_data), | |
| 288 data['imports']) | |
| 289 module.enums = map( | |
| 290 lambda enum: EnumFromData(module, enum, None), data['enums']) | |
| 291 module.structs = map( | |
| 292 lambda struct: StructFromData(module, struct), data['structs']) | |
| 293 module.interfaces = map( | |
| 294 lambda interface: InterfaceFromData(module, interface), | |
| 295 data['interfaces']) | |
| 296 | |
| 297 return module | |
| 298 | |
| 299 def OrderedModuleFromData(data): | |
| 300 module = ModuleFromData(data) | |
| 301 next_interface_ordinal = 0 | |
| 302 for interface in module.interfaces: | |
| 303 next_ordinal = 0 | |
| 304 for method in interface.methods: | |
| 305 if method.ordinal is None: | |
| 306 method.ordinal = next_ordinal | |
| 307 next_ordinal = method.ordinal + 1 | |
| 308 return module | |
| OLD | NEW |