| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 """Convert parse tree to AST. | 5 """Convert parse tree to AST. |
| 6 | 6 |
| 7 This module converts the parse tree to the AST we use for code generation. The | 7 This module converts the parse tree to the AST we use for code generation. The |
| 8 main entry point is OrderedModule, which gets passed the parser | 8 main entry point is OrderedModule, which gets passed the parser |
| 9 representation of a mojom file. When called it's assumed that all imports have | 9 representation of a mojom file. When called it's assumed that all imports have |
| 10 already been parsed and converted to ASTs before. | 10 already been parsed and converted to ASTs before. |
| 11 """ | 11 """ |
| 12 | 12 |
| 13 import copy | 13 import os |
| 14 import re | 14 import re |
| 15 | 15 |
| 16 import module as mojom | 16 import module as mojom |
| 17 from mojom.parse import ast | 17 from mojom.parse import ast |
| 18 | 18 |
| 19 def _DuplicateName(values): | 19 def _DuplicateName(values): |
| 20 """Returns the 'name' of the first entry in |values| whose 'name' has already | 20 """Returns the 'mojom_name' of the first entry in |values| whose 'mojom_name' |
| 21 been encountered. If there are no duplicates, returns None.""" | 21 has already been encountered. If there are no duplicates, returns None.""" |
| 22 names = set() | 22 names = set() |
| 23 for value in values: | 23 for value in values: |
| 24 if value.name in names: | 24 if value.mojom_name in names: |
| 25 return value.name | 25 return value.mojom_name |
| 26 names.add(value.name) | 26 names.add(value.mojom_name) |
| 27 return None | 27 return None |
| 28 | 28 |
| 29 def _ElemsOfType(elems, elem_type, scope): | 29 def _ElemsOfType(elems, elem_type, scope): |
| 30 """Find all elements of the given type. | 30 """Find all elements of the given type. |
| 31 | 31 |
| 32 Args: | 32 Args: |
| 33 elems: {Sequence[Any]} Sequence of elems. | 33 elems: {Sequence[Any]} Sequence of elems. |
| 34 elem_type: {Type[C]} Extract all elems of this type. | 34 elem_type: {Type[C]} Extract all elems of this type. |
| 35 scope: {str} The name of the surrounding scope (e.g. struct | 35 scope: {str} The name of the surrounding scope (e.g. struct |
| 36 definition). Used in error messages. | 36 definition). Used in error messages. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 """Tries to find which Kind a spec refers to, given the scope in which its | 114 """Tries to find which Kind a spec refers to, given the scope in which its |
| 115 referenced. Starts checking from the narrowest scope to most general. For | 115 referenced. Starts checking from the narrowest scope to most general. For |
| 116 example, given a struct field like | 116 example, given a struct field like |
| 117 Foo.Bar x; | 117 Foo.Bar x; |
| 118 Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner | 118 Foo.Bar could refer to the type 'Bar' in the 'Foo' namespace, or an inner |
| 119 type 'Bar' in the struct 'Foo' in the current namespace. | 119 type 'Bar' in the struct 'Foo' in the current namespace. |
| 120 | 120 |
| 121 |scope| is a tuple that looks like (namespace, struct/interface), referring | 121 |scope| is a tuple that looks like (namespace, struct/interface), referring |
| 122 to the location where the type is referenced.""" | 122 to the location where the type is referenced.""" |
| 123 if spec.startswith('x:'): | 123 if spec.startswith('x:'): |
| 124 name = spec[2:] | 124 mojom_name = spec[2:] |
| 125 for i in xrange(len(scope), -1, -1): | 125 for i in xrange(len(scope), -1, -1): |
| 126 test_spec = 'x:' | 126 test_spec = 'x:' |
| 127 if i > 0: | 127 if i > 0: |
| 128 test_spec += '.'.join(scope[:i]) + '.' | 128 test_spec += '.'.join(scope[:i]) + '.' |
| 129 test_spec += name | 129 test_spec += mojom_name |
| 130 kind = kinds.get(test_spec) | 130 kind = kinds.get(test_spec) |
| 131 if kind: | 131 if kind: |
| 132 return kind | 132 return kind |
| 133 | 133 |
| 134 return kinds.get(spec) | 134 return kinds.get(spec) |
| 135 | 135 |
| 136 def _LookupValue(values, name, scope, kind): | 136 def _LookupValue(values, mojom_name, scope, kind): |
| 137 """Like LookupKind, but for constant values.""" | 137 """Like LookupKind, but for constant values.""" |
| 138 # If the type is an enum, the value can be specified as a qualified name, in | 138 # If the type is an enum, the value can be specified as a qualified name, in |
| 139 # which case the form EnumName.ENUM_VALUE must be used. We use the presence | 139 # which case the form EnumName.ENUM_VALUE must be used. We use the presence |
| 140 # of a '.' in the requested name to identify this. Otherwise, we prepend the | 140 # of a '.' in the requested name to identify this. Otherwise, we prepend the |
| 141 # enum name. | 141 # enum name. |
| 142 if isinstance(kind, mojom.Enum) and '.' not in name: | 142 if isinstance(kind, mojom.Enum) and '.' not in mojom_name: |
| 143 name = '%s.%s' % (kind.spec.split(':', 1)[1], name) | 143 mojom_name = '%s.%s' % (kind.spec.split(':', 1)[1], mojom_name) |
| 144 for i in reversed(xrange(len(scope) + 1)): | 144 for i in reversed(xrange(len(scope) + 1)): |
| 145 test_spec = '.'.join(scope[:i]) | 145 test_spec = '.'.join(scope[:i]) |
| 146 if test_spec: | 146 if test_spec: |
| 147 test_spec += '.' | 147 test_spec += '.' |
| 148 test_spec += name | 148 test_spec += mojom_name |
| 149 value = values.get(test_spec) | 149 value = values.get(test_spec) |
| 150 if value: | 150 if value: |
| 151 return value | 151 return value |
| 152 | 152 |
| 153 return values.get(name) | 153 return values.get(mojom_name) |
| 154 | 154 |
| 155 def _FixupExpression(module, value, scope, kind): | 155 def _FixupExpression(module, value, scope, kind): |
| 156 """Translates an IDENTIFIER into a built-in value or structured NamedValue | 156 """Translates an IDENTIFIER into a built-in value or structured NamedValue |
| 157 object.""" | 157 object.""" |
| 158 if isinstance(value, tuple) and value[0] == 'IDENTIFIER': | 158 if isinstance(value, tuple) and value[0] == 'IDENTIFIER': |
| 159 # Allow user defined values to shadow builtins. | 159 # Allow user defined values to shadow builtins. |
| 160 result = _LookupValue(module.values, value[1], scope, kind) | 160 result = _LookupValue(module.values, value[1], scope, kind) |
| 161 if result: | 161 if result: |
| 162 if isinstance(result, tuple): | 162 if isinstance(result, tuple): |
| 163 raise Exception('Unable to resolve expression: %r' % value[1]) | 163 raise Exception('Unable to resolve expression: %r' % value[1]) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 def _Struct(module, parsed_struct): | 239 def _Struct(module, parsed_struct): |
| 240 """ | 240 """ |
| 241 Args: | 241 Args: |
| 242 module: {mojom.Module} Module currently being constructed. | 242 module: {mojom.Module} Module currently being constructed. |
| 243 parsed_struct: {ast.Struct} Parsed struct. | 243 parsed_struct: {ast.Struct} Parsed struct. |
| 244 | 244 |
| 245 Returns: | 245 Returns: |
| 246 {mojom.Struct} AST struct. | 246 {mojom.Struct} AST struct. |
| 247 """ | 247 """ |
| 248 struct = mojom.Struct(module=module) | 248 struct = mojom.Struct(module=module) |
| 249 struct.name = parsed_struct.name | 249 struct.mojom_name = parsed_struct.mojom_name |
| 250 struct.native_only = parsed_struct.body is None | 250 struct.native_only = parsed_struct.body is None |
| 251 struct.spec = 'x:' + module.namespace + '.' + struct.name | 251 struct.spec = 'x:' + module.mojom_namespace + '.' + struct.mojom_name |
| 252 module.kinds[struct.spec] = struct | 252 module.kinds[struct.spec] = struct |
| 253 if struct.native_only: | 253 if struct.native_only: |
| 254 struct.enums = [] | 254 struct.enums = [] |
| 255 struct.constants = [] | 255 struct.constants = [] |
| 256 struct.fields_data = [] | 256 struct.fields_data = [] |
| 257 else: | 257 else: |
| 258 struct.enums = map( | 258 struct.enums = map( |
| 259 lambda enum: _Enum(module, enum, struct), | 259 lambda enum: _Enum(module, enum, struct), |
| 260 _ElemsOfType(parsed_struct.body, ast.Enum, parsed_struct.name)) | 260 _ElemsOfType(parsed_struct.body, ast.Enum, parsed_struct.mojom_name)) |
| 261 struct.constants = map( | 261 struct.constants = map( |
| 262 lambda constant: _Constant(module, constant, struct), | 262 lambda constant: _Constant(module, constant, struct), |
| 263 _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.name)) | 263 _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.mojom_name)) |
| 264 # Stash fields parsed_struct here temporarily. | 264 # Stash fields parsed_struct here temporarily. |
| 265 struct.fields_data = _ElemsOfType( | 265 struct.fields_data = _ElemsOfType( |
| 266 parsed_struct.body, ast.StructField, parsed_struct.name) | 266 parsed_struct.body, ast.StructField, parsed_struct.mojom_name) |
| 267 struct.attributes = _AttributeListToDict(parsed_struct.attribute_list) | 267 struct.attributes = _AttributeListToDict(parsed_struct.attribute_list) |
| 268 | 268 |
| 269 # Enforce that a [Native] attribute is set to make native-only struct | 269 # Enforce that a [Native] attribute is set to make native-only struct |
| 270 # declarations more explicit. | 270 # declarations more explicit. |
| 271 if struct.native_only: | 271 if struct.native_only: |
| 272 if not struct.attributes or not struct.attributes.get('Native', False): | 272 if not struct.attributes or not struct.attributes.get('Native', False): |
| 273 raise Exception("Native-only struct declarations must include a " + | 273 raise Exception("Native-only struct declarations must include a " + |
| 274 "Native attribute.") | 274 "Native attribute.") |
| 275 | 275 |
| 276 return struct | 276 return struct |
| 277 | 277 |
| 278 def _Union(module, parsed_union): | 278 def _Union(module, parsed_union): |
| 279 """ | 279 """ |
| 280 Args: | 280 Args: |
| 281 module: {mojom.Module} Module currently being constructed. | 281 module: {mojom.Module} Module currently being constructed. |
| 282 parsed_union: {ast.Union} Parsed union. | 282 parsed_union: {ast.Union} Parsed union. |
| 283 | 283 |
| 284 Returns: | 284 Returns: |
| 285 {mojom.Union} AST union. | 285 {mojom.Union} AST union. |
| 286 """ | 286 """ |
| 287 union = mojom.Union(module=module) | 287 union = mojom.Union(module=module) |
| 288 union.name = parsed_union.name | 288 union.mojom_name = parsed_union.mojom_name |
| 289 union.spec = 'x:' + module.namespace + '.' + union.name | 289 union.spec = 'x:' + module.mojom_namespace + '.' + union.mojom_name |
| 290 module.kinds[union.spec] = union | 290 module.kinds[union.spec] = union |
| 291 # Stash fields parsed_union here temporarily. | 291 # Stash fields parsed_union here temporarily. |
| 292 union.fields_data = _ElemsOfType( | 292 union.fields_data = _ElemsOfType( |
| 293 parsed_union.body, ast.UnionField, parsed_union.name) | 293 parsed_union.body, ast.UnionField, parsed_union.mojom_name) |
| 294 union.attributes = _AttributeListToDict(parsed_union.attribute_list) | 294 union.attributes = _AttributeListToDict(parsed_union.attribute_list) |
| 295 return union | 295 return union |
| 296 | 296 |
| 297 def _StructField(module, parsed_field, struct): | 297 def _StructField(module, parsed_field, struct): |
| 298 """ | 298 """ |
| 299 Args: | 299 Args: |
| 300 module: {mojom.Module} Module currently being constructed. | 300 module: {mojom.Module} Module currently being constructed. |
| 301 parsed_field: {ast.StructField} Parsed struct field. | 301 parsed_field: {ast.StructField} Parsed struct field. |
| 302 struct: {mojom.Struct} Struct this field belongs to. | 302 struct: {mojom.Struct} Struct this field belongs to. |
| 303 | 303 |
| 304 Returns: | 304 Returns: |
| 305 {mojom.StructField} AST struct field. | 305 {mojom.StructField} AST struct field. |
| 306 """ | 306 """ |
| 307 field = mojom.StructField() | 307 field = mojom.StructField() |
| 308 field.name = parsed_field.name | 308 field.mojom_name = parsed_field.mojom_name |
| 309 field.kind = _Kind( | 309 field.kind = _Kind( |
| 310 module.kinds, _MapKind(parsed_field.typename), | 310 module.kinds, _MapKind(parsed_field.typename), |
| 311 (module.namespace, struct.name)) | 311 (module.mojom_namespace, struct.mojom_name)) |
| 312 field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None | 312 field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None |
| 313 field.default = _FixupExpression( | 313 field.default = _FixupExpression( |
| 314 module, parsed_field.default_value, (module.namespace, struct.name), | 314 module, parsed_field.default_value, |
| 315 field.kind) | 315 (module.mojom_namespace, struct.mojom_name), field.kind) |
| 316 field.attributes = _AttributeListToDict(parsed_field.attribute_list) | 316 field.attributes = _AttributeListToDict(parsed_field.attribute_list) |
| 317 return field | 317 return field |
| 318 | 318 |
| 319 def _UnionField(module, parsed_field, union): | 319 def _UnionField(module, parsed_field, union): |
| 320 """ | 320 """ |
| 321 Args: | 321 Args: |
| 322 module: {mojom.Module} Module currently being constructed. | 322 module: {mojom.Module} Module currently being constructed. |
| 323 parsed_field: {ast.UnionField} Parsed union field. | 323 parsed_field: {ast.UnionField} Parsed union field. |
| 324 union: {mojom.Union} Union this fields belong to. | 324 union: {mojom.Union} Union this fields belong to. |
| 325 | 325 |
| 326 Returns: | 326 Returns: |
| 327 {mojom.UnionField} AST union. | 327 {mojom.UnionField} AST union. |
| 328 """ | 328 """ |
| 329 field = mojom.UnionField() | 329 field = mojom.UnionField() |
| 330 field.name = parsed_field.name | 330 field.mojom_name = parsed_field.mojom_name |
| 331 field.kind = _Kind( | 331 field.kind = _Kind( |
| 332 module.kinds, _MapKind(parsed_field.typename), | 332 module.kinds, _MapKind(parsed_field.typename), |
| 333 (module.namespace, union.name)) | 333 (module.mojom_namespace, union.mojom_name)) |
| 334 field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None | 334 field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None |
| 335 field.default = _FixupExpression( | 335 field.default = _FixupExpression( |
| 336 module, None, (module.namespace, union.name), field.kind) | 336 module, None, (module.mojom_namespace, union.mojom_name), field.kind) |
| 337 field.attributes = _AttributeListToDict(parsed_field.attribute_list) | 337 field.attributes = _AttributeListToDict(parsed_field.attribute_list) |
| 338 return field | 338 return field |
| 339 | 339 |
| 340 def _Parameter(module, parsed_param, interface): | 340 def _Parameter(module, parsed_param, interface): |
| 341 """ | 341 """ |
| 342 Args: | 342 Args: |
| 343 module: {mojom.Module} Module currently being constructed. | 343 module: {mojom.Module} Module currently being constructed. |
| 344 parsed_param: {ast.Parameter} Parsed parameter. | 344 parsed_param: {ast.Parameter} Parsed parameter. |
| 345 union: {mojom.Interface} Interface this parameter belongs to. | 345 union: {mojom.Interface} Interface this parameter belongs to. |
| 346 | 346 |
| 347 Returns: | 347 Returns: |
| 348 {mojom.Parameter} AST parameter. | 348 {mojom.Parameter} AST parameter. |
| 349 """ | 349 """ |
| 350 parameter = mojom.Parameter() | 350 parameter = mojom.Parameter() |
| 351 parameter.name = parsed_param.name | 351 parameter.mojom_name = parsed_param.mojom_name |
| 352 parameter.kind = _Kind( | 352 parameter.kind = _Kind( |
| 353 module.kinds, _MapKind(parsed_param.typename), | 353 module.kinds, _MapKind(parsed_param.typename), |
| 354 (module.namespace, interface.name)) | 354 (module.mojom_namespace, interface.mojom_name)) |
| 355 parameter.ordinal = ( | 355 parameter.ordinal = ( |
| 356 parsed_param.ordinal.value if parsed_param.ordinal else None) | 356 parsed_param.ordinal.value if parsed_param.ordinal else None) |
| 357 parameter.default = None # TODO(tibell): We never have these. Remove field? | 357 parameter.default = None # TODO(tibell): We never have these. Remove field? |
| 358 parameter.attributes = _AttributeListToDict(parsed_param.attribute_list) | 358 parameter.attributes = _AttributeListToDict(parsed_param.attribute_list) |
| 359 return parameter | 359 return parameter |
| 360 | 360 |
| 361 def _Method(module, parsed_method, interface): | 361 def _Method(module, parsed_method, interface): |
| 362 """ | 362 """ |
| 363 Args: | 363 Args: |
| 364 module: {mojom.Module} Module currently being constructed. | 364 module: {mojom.Module} Module currently being constructed. |
| 365 parsed_method: {ast.Method} Parsed method. | 365 parsed_method: {ast.Method} Parsed method. |
| 366 interface: {mojom.Interface} Interface this method belongs to. | 366 interface: {mojom.Interface} Interface this method belongs to. |
| 367 | 367 |
| 368 Returns: | 368 Returns: |
| 369 {mojom.Method} AST method. | 369 {mojom.Method} AST method. |
| 370 """ | 370 """ |
| 371 method = mojom.Method( | 371 method = mojom.Method( |
| 372 interface, parsed_method.name, | 372 interface, parsed_method.mojom_name, |
| 373 ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None) | 373 ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None) |
| 374 method.parameters = map( | 374 method.parameters = map( |
| 375 lambda parameter: _Parameter(module, parameter, interface), | 375 lambda parameter: _Parameter(module, parameter, interface), |
| 376 parsed_method.parameter_list) | 376 parsed_method.parameter_list) |
| 377 if parsed_method.response_parameter_list is not None: | 377 if parsed_method.response_parameter_list is not None: |
| 378 method.response_parameters = map( | 378 method.response_parameters = map( |
| 379 lambda parameter: _Parameter(module, parameter, interface), | 379 lambda parameter: _Parameter(module, parameter, interface), |
| 380 parsed_method.response_parameter_list) | 380 parsed_method.response_parameter_list) |
| 381 method.attributes = _AttributeListToDict(parsed_method.attribute_list) | 381 method.attributes = _AttributeListToDict(parsed_method.attribute_list) |
| 382 | 382 |
| 383 # Enforce that only methods with response can have a [Sync] attribute. | 383 # Enforce that only methods with response can have a [Sync] attribute. |
| 384 if method.sync and method.response_parameters is None: | 384 if method.sync and method.response_parameters is None: |
| 385 raise Exception("Only methods with response can include a [Sync] " | 385 raise Exception("Only methods with response can include a [Sync] " |
| 386 "attribute. If no response parameters are needed, you " | 386 "attribute. If no response parameters are needed, you " |
| 387 "could use an empty response parameter list, i.e., " | 387 "could use an empty response parameter list, i.e., " |
| 388 "\"=> ()\".") | 388 "\"=> ()\".") |
| 389 | 389 |
| 390 return method | 390 return method |
| 391 | 391 |
| 392 def _Interface(module, parsed_iface): | 392 def _Interface(module, parsed_iface): |
| 393 """ | 393 """ |
| 394 Args: | 394 Args: |
| 395 module: {mojom.Module} Module currently being constructed. | 395 module: {mojom.Module} Module currently being constructed. |
| 396 parsed_iface: {ast.Interface} Parsed interface. | 396 parsed_iface: {ast.Interface} Parsed interface. |
| 397 | 397 |
| 398 Returns: | 398 Returns: |
| 399 {mojom.Interface} AST interface. | 399 {mojom.Interface} AST interface. |
| 400 """ | 400 """ |
| 401 interface = mojom.Interface(module=module) | 401 interface = mojom.Interface(module=module) |
| 402 interface.name = parsed_iface.name | 402 interface.mojom_name = parsed_iface.mojom_name |
| 403 interface.spec = 'x:' + module.namespace + '.' + interface.name | 403 interface.spec = 'x:' + module.mojom_namespace + '.' + interface.mojom_name |
| 404 module.kinds[interface.spec] = interface | 404 module.kinds[interface.spec] = interface |
| 405 interface.enums = map( | 405 interface.enums = map( |
| 406 lambda enum: _Enum(module, enum, interface), | 406 lambda enum: _Enum(module, enum, interface), |
| 407 _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.name)) | 407 _ElemsOfType(parsed_iface.body, ast.Enum, parsed_iface.mojom_name)) |
| 408 interface.constants = map( | 408 interface.constants = map( |
| 409 lambda constant: _Constant(module, constant, interface), | 409 lambda constant: _Constant(module, constant, interface), |
| 410 _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.name)) | 410 _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.mojom_name)) |
| 411 # Stash methods parsed_iface here temporarily. | 411 # Stash methods parsed_iface here temporarily. |
| 412 interface.methods_data = _ElemsOfType( | 412 interface.methods_data = _ElemsOfType( |
| 413 parsed_iface.body, ast.Method, parsed_iface.name) | 413 parsed_iface.body, ast.Method, parsed_iface.mojom_name) |
| 414 interface.attributes = _AttributeListToDict(parsed_iface.attribute_list) | 414 interface.attributes = _AttributeListToDict(parsed_iface.attribute_list) |
| 415 return interface | 415 return interface |
| 416 | 416 |
| 417 def _EnumField(module, enum, parsed_field, parent_kind): | 417 def _EnumField(module, enum, parsed_field, parent_kind): |
| 418 """ | 418 """ |
| 419 Args: | 419 Args: |
| 420 module: {mojom.Module} Module currently being constructed. | 420 module: {mojom.Module} Module currently being constructed. |
| 421 enum: {mojom.Enum} Enum this field belongs to. | 421 enum: {mojom.Enum} Enum this field belongs to. |
| 422 parsed_field: {ast.EnumValue} Parsed enum value. | 422 parsed_field: {ast.EnumValue} Parsed enum value. |
| 423 parent_kind: {mojom.Kind} The enclosing type. | 423 parent_kind: {mojom.Kind} The enclosing type. |
| 424 | 424 |
| 425 Returns: | 425 Returns: |
| 426 {mojom.EnumField} AST enum field. | 426 {mojom.EnumField} AST enum field. |
| 427 """ | 427 """ |
| 428 field = mojom.EnumField() | 428 field = mojom.EnumField() |
| 429 field.name = parsed_field.name | 429 field.mojom_name = parsed_field.mojom_name |
| 430 # TODO(mpcomplete): FixupExpression should be done in the second pass, | 430 # TODO(mpcomplete): FixupExpression should be done in the second pass, |
| 431 # so constants and enums can refer to each other. | 431 # so constants and enums can refer to each other. |
| 432 # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or | 432 # TODO(mpcomplete): But then, what if constants are initialized to an enum? Or |
| 433 # vice versa? | 433 # vice versa? |
| 434 if parent_kind: | 434 if parent_kind: |
| 435 field.value = _FixupExpression( | 435 field.value = _FixupExpression( |
| 436 module, parsed_field.value, (module.namespace, parent_kind.name), enum) | 436 module, parsed_field.value, |
| 437 (module.mojom_namespace, parent_kind.mojom_name), enum) |
| 437 else: | 438 else: |
| 438 field.value = _FixupExpression( | 439 field.value = _FixupExpression( |
| 439 module, parsed_field.value, (module.namespace, ), enum) | 440 module, parsed_field.value, (module.mojom_namespace, ), enum) |
| 440 field.attributes = _AttributeListToDict(parsed_field.attribute_list) | 441 field.attributes = _AttributeListToDict(parsed_field.attribute_list) |
| 441 value = mojom.EnumValue(module, enum, field) | 442 value = mojom.EnumValue(module, enum, field) |
| 442 module.values[value.GetSpec()] = value | 443 module.values[value.GetSpec()] = value |
| 443 return field | 444 return field |
| 444 | 445 |
| 445 def _ResolveNumericEnumValues(enum_fields): | 446 def _ResolveNumericEnumValues(enum_fields): |
| 446 """ | 447 """ |
| 447 Given a reference to a list of mojom.EnumField, resolves and assigns their | 448 Given a reference to a list of mojom.EnumField, resolves and assigns their |
| 448 values to EnumField.numeric_value. | 449 values to EnumField.numeric_value. |
| 449 """ | 450 """ |
| 450 | 451 |
| 451 # map of <name> -> integral value | 452 # map of <mojom_name> -> integral value |
| 452 resolved_enum_values = {} | 453 resolved_enum_values = {} |
| 453 prev_value = -1 | 454 prev_value = -1 |
| 454 for field in enum_fields: | 455 for field in enum_fields: |
| 455 # This enum value is +1 the previous enum value (e.g: BEGIN). | 456 # This enum value is +1 the previous enum value (e.g: BEGIN). |
| 456 if field.value is None: | 457 if field.value is None: |
| 457 prev_value += 1 | 458 prev_value += 1 |
| 458 | 459 |
| 459 # Integral value (e.g: BEGIN = -0x1). | 460 # Integral value (e.g: BEGIN = -0x1). |
| 460 elif type(field.value) is str: | 461 elif type(field.value) is str: |
| 461 prev_value = int(field.value, 0) | 462 prev_value = int(field.value, 0) |
| 462 | 463 |
| 463 # Reference to a previous enum value (e.g: INIT = BEGIN). | 464 # Reference to a previous enum value (e.g: INIT = BEGIN). |
| 464 elif type(field.value) is mojom.EnumValue: | 465 elif type(field.value) is mojom.EnumValue: |
| 465 prev_value = resolved_enum_values[field.value.name] | 466 prev_value = resolved_enum_values[field.value.mojom_name] |
| 466 else: | 467 else: |
| 467 raise Exception("Unresolved enum value.") | 468 raise Exception("Unresolved enum value.") |
| 468 | 469 |
| 469 resolved_enum_values[field.name] = prev_value | 470 resolved_enum_values[field.mojom_name] = prev_value |
| 470 field.numeric_value = prev_value | 471 field.numeric_value = prev_value |
| 471 | 472 |
| 472 def _Enum(module, parsed_enum, parent_kind): | 473 def _Enum(module, parsed_enum, parent_kind): |
| 473 """ | 474 """ |
| 474 Args: | 475 Args: |
| 475 module: {mojom.Module} Module currently being constructed. | 476 module: {mojom.Module} Module currently being constructed. |
| 476 parsed_enum: {ast.Enum} Parsed enum. | 477 parsed_enum: {ast.Enum} Parsed enum. |
| 477 | 478 |
| 478 Returns: | 479 Returns: |
| 479 {mojom.Enum} AST enum. | 480 {mojom.Enum} AST enum. |
| 480 """ | 481 """ |
| 481 enum = mojom.Enum(module=module) | 482 enum = mojom.Enum(module=module) |
| 482 enum.name = parsed_enum.name | 483 enum.mojom_name = parsed_enum.mojom_name |
| 483 enum.native_only = parsed_enum.enum_value_list is None | 484 enum.native_only = parsed_enum.enum_value_list is None |
| 484 name = enum.name | 485 mojom_name = enum.mojom_name |
| 485 if parent_kind: | 486 if parent_kind: |
| 486 name = parent_kind.name + '.' + name | 487 mojom_name = parent_kind.mojom_name + '.' + mojom_name |
| 487 enum.spec = 'x:%s.%s' % (module.namespace, name) | 488 enum.spec = 'x:%s.%s' % (module.mojom_namespace, mojom_name) |
| 488 enum.parent_kind = parent_kind | 489 enum.parent_kind = parent_kind |
| 489 enum.attributes = _AttributeListToDict(parsed_enum.attribute_list) | 490 enum.attributes = _AttributeListToDict(parsed_enum.attribute_list) |
| 490 if enum.native_only: | 491 if enum.native_only: |
| 491 enum.fields = [] | 492 enum.fields = [] |
| 492 else: | 493 else: |
| 493 enum.fields = map( | 494 enum.fields = map( |
| 494 lambda field: _EnumField(module, enum, field, parent_kind), | 495 lambda field: _EnumField(module, enum, field, parent_kind), |
| 495 parsed_enum.enum_value_list) | 496 parsed_enum.enum_value_list) |
| 496 _ResolveNumericEnumValues(enum.fields) | 497 _ResolveNumericEnumValues(enum.fields) |
| 497 | 498 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 509 def _Constant(module, parsed_const, parent_kind): | 510 def _Constant(module, parsed_const, parent_kind): |
| 510 """ | 511 """ |
| 511 Args: | 512 Args: |
| 512 module: {mojom.Module} Module currently being constructed. | 513 module: {mojom.Module} Module currently being constructed. |
| 513 parsed_const: {ast.Const} Parsed constant. | 514 parsed_const: {ast.Const} Parsed constant. |
| 514 | 515 |
| 515 Returns: | 516 Returns: |
| 516 {mojom.Constant} AST constant. | 517 {mojom.Constant} AST constant. |
| 517 """ | 518 """ |
| 518 constant = mojom.Constant() | 519 constant = mojom.Constant() |
| 519 constant.name = parsed_const.name | 520 constant.mojom_name = parsed_const.mojom_name |
| 520 if parent_kind: | 521 if parent_kind: |
| 521 scope = (module.namespace, parent_kind.name) | 522 scope = (module.mojom_namespace, parent_kind.mojom_name) |
| 522 else: | 523 else: |
| 523 scope = (module.namespace, ) | 524 scope = (module.mojom_namespace, ) |
| 524 # TODO(mpcomplete): maybe we should only support POD kinds. | 525 # TODO(mpcomplete): maybe we should only support POD kinds. |
| 525 constant.kind = _Kind(module.kinds, _MapKind(parsed_const.typename), scope) | 526 constant.kind = _Kind(module.kinds, _MapKind(parsed_const.typename), scope) |
| 526 constant.parent_kind = parent_kind | 527 constant.parent_kind = parent_kind |
| 527 constant.value = _FixupExpression(module, parsed_const.value, scope, None) | 528 constant.value = _FixupExpression(module, parsed_const.value, scope, None) |
| 528 | 529 |
| 529 value = mojom.ConstantValue(module, parent_kind, constant) | 530 value = mojom.ConstantValue(module, parent_kind, constant) |
| 530 module.values[value.GetSpec()] = value | 531 module.values[value.GetSpec()] = value |
| 531 return constant | 532 return constant |
| 532 | 533 |
| 533 def _Module(tree, name, imports): | 534 def _Module(tree, path, imports): |
| 534 """ | 535 """ |
| 535 Args: | 536 Args: |
| 536 tree: {ast.Mojom} The parse tree. | 537 tree: {ast.Mojom} The parse tree. |
| 537 name: {str} The mojom filename, excluding the path. | 538 path: {str} The path to the mojom file. |
| 538 imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in | 539 imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in |
| 539 the import list, to already processed modules. Used to process imports. | 540 the import list, to already processed modules. Used to process imports. |
| 540 | 541 |
| 541 Returns: | 542 Returns: |
| 542 {mojom.Module} An AST for the mojom. | 543 {mojom.Module} An AST for the mojom. |
| 543 """ | 544 """ |
| 544 module = mojom.Module() | 545 module = mojom.Module(path=path) |
| 545 module.kinds = {} | 546 module.kinds = {} |
| 546 for kind in mojom.PRIMITIVES: | 547 for kind in mojom.PRIMITIVES: |
| 547 module.kinds[kind.spec] = kind | 548 module.kinds[kind.spec] = kind |
| 548 | 549 |
| 549 module.values = {} | 550 module.values = {} |
| 550 | 551 |
| 551 module.name = name | 552 module.mojom_namespace = tree.module.mojom_namespace[1] if tree.module else '' |
| 552 module.namespace = tree.module.name[1] if tree.module else '' | |
| 553 # Imports must come first, because they add to module.kinds which is used | 553 # Imports must come first, because they add to module.kinds which is used |
| 554 # by by the others. | 554 # by by the others. |
| 555 module.imports = [ | 555 module.imports = [ |
| 556 _Import(module, imports[imp.import_filename]) | 556 _Import(module, imports[imp.import_filename]) |
| 557 for imp in tree.import_list] | 557 for imp in tree.import_list] |
| 558 if tree.module and tree.module.attribute_list: | 558 if tree.module and tree.module.attribute_list: |
| 559 assert isinstance(tree.module.attribute_list, ast.AttributeList) | 559 assert isinstance(tree.module.attribute_list, ast.AttributeList) |
| 560 # TODO(vtl): Check for duplicate keys here. | 560 # TODO(vtl): Check for duplicate keys here. |
| 561 module.attributes = dict((attribute.key, attribute.value) | 561 module.attributes = dict((attribute.key, attribute.value) |
| 562 for attribute in tree.module.attribute_list) | 562 for attribute in tree.module.attribute_list) |
| 563 | 563 |
| 564 filename = os.path.basename(path) |
| 564 # First pass collects kinds. | 565 # First pass collects kinds. |
| 565 module.enums = map( | 566 module.enums = map( |
| 566 lambda enum: _Enum(module, enum, None), | 567 lambda enum: _Enum(module, enum, None), |
| 567 _ElemsOfType(tree.definition_list, ast.Enum, name)) | 568 _ElemsOfType(tree.definition_list, ast.Enum, filename)) |
| 568 module.structs = map( | 569 module.structs = map( |
| 569 lambda struct: _Struct(module, struct), | 570 lambda struct: _Struct(module, struct), |
| 570 _ElemsOfType(tree.definition_list, ast.Struct, name)) | 571 _ElemsOfType(tree.definition_list, ast.Struct, filename)) |
| 571 module.unions = map( | 572 module.unions = map( |
| 572 lambda union: _Union(module, union), | 573 lambda union: _Union(module, union), |
| 573 _ElemsOfType(tree.definition_list, ast.Union, name)) | 574 _ElemsOfType(tree.definition_list, ast.Union, filename)) |
| 574 module.interfaces = map( | 575 module.interfaces = map( |
| 575 lambda interface: _Interface(module, interface), | 576 lambda interface: _Interface(module, interface), |
| 576 _ElemsOfType(tree.definition_list, ast.Interface, name)) | 577 _ElemsOfType(tree.definition_list, ast.Interface, filename)) |
| 577 module.constants = map( | 578 module.constants = map( |
| 578 lambda constant: _Constant(module, constant, None), | 579 lambda constant: _Constant(module, constant, None), |
| 579 _ElemsOfType(tree.definition_list, ast.Const, name)) | 580 _ElemsOfType(tree.definition_list, ast.Const, filename)) |
| 580 | 581 |
| 581 # Second pass expands fields and methods. This allows fields and parameters | 582 # Second pass expands fields and methods. This allows fields and parameters |
| 582 # to refer to kinds defined anywhere in the mojom. | 583 # to refer to kinds defined anywhere in the mojom. |
| 583 for struct in module.structs: | 584 for struct in module.structs: |
| 584 struct.fields = map(lambda field: | 585 struct.fields = map(lambda field: |
| 585 _StructField(module, field, struct), struct.fields_data) | 586 _StructField(module, field, struct), struct.fields_data) |
| 586 del struct.fields_data | 587 del struct.fields_data |
| 587 for union in module.unions: | 588 for union in module.unions: |
| 588 union.fields = map(lambda field: | 589 union.fields = map(lambda field: |
| 589 _UnionField(module, field, union), union.fields_data) | 590 _UnionField(module, field, union), union.fields_data) |
| 590 del union.fields_data | 591 del union.fields_data |
| 591 for interface in module.interfaces: | 592 for interface in module.interfaces: |
| 592 interface.methods = map(lambda method: | 593 interface.methods = map(lambda method: |
| 593 _Method(module, method, interface), interface.methods_data) | 594 _Method(module, method, interface), interface.methods_data) |
| 594 del interface.methods_data | 595 del interface.methods_data |
| 595 | 596 |
| 596 return module | 597 return module |
| 597 | 598 |
| 598 def OrderedModule(tree, name, imports): | 599 def OrderedModule(tree, path, imports): |
| 599 """Convert parse tree to AST module. | 600 """Convert parse tree to AST module. |
| 600 | 601 |
| 601 Args: | 602 Args: |
| 602 tree: {ast.Mojom} The parse tree. | 603 tree: {ast.Mojom} The parse tree. |
| 603 name: {str} The mojom filename, excluding the path. | 604 path: {str} The path to the mojom file. |
| 604 imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in | 605 imports: {Dict[str, mojom.Module]} Mapping from filenames, as they appear in |
| 605 the import list, to already processed modules. Used to process imports. | 606 the import list, to already processed modules. Used to process imports. |
| 606 | 607 |
| 607 Returns: | 608 Returns: |
| 608 {mojom.Module} An AST for the mojom. | 609 {mojom.Module} An AST for the mojom. |
| 609 """ | 610 """ |
| 610 module = _Module(tree, name, imports) | 611 module = _Module(tree, path, imports) |
| 611 return module | 612 return module |
| OLD | NEW |