| 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 """Translates parse tree to Mojom IR.""" | 5 """Translates parse tree to Mojom IR.""" |
| 6 | 6 |
| 7 | 7 |
| 8 import re | 8 import re |
| 9 | 9 |
| 10 from . import ast | 10 from . import ast |
| 11 | 11 |
| 12 | 12 |
| 13 def _MapTreeForType(func, tree, type_to_map): | 13 def _MapTreeForType(func, tree, type_to_map): |
| 14 assert isinstance(type_to_map, type) | 14 assert isinstance(type_to_map, type) |
| 15 if not tree: | 15 if not tree: |
| 16 return [] | 16 return [] |
| 17 return [func(subtree) for subtree in tree if isinstance(subtree, type_to_map)] | 17 return [func(subtree) for subtree in tree if isinstance(subtree, type_to_map)] |
| 18 | 18 |
| 19 _FIXED_ARRAY_REGEXP = re.compile(r'\[[0-9]+\]') | 19 _FIXED_ARRAY_REGEXP = re.compile(r'\[[0-9]+\]') |
| 20 | 20 |
| 21 def _MapKind(kind): | 21 def MapKind(kind): |
| 22 map_to_kind = {'bool': 'b', | 22 map_to_kind = {'bool': 'b', |
| 23 'int8': 'i8', | 23 'int8': 'i8', |
| 24 'int16': 'i16', | 24 'int16': 'i16', |
| 25 'int32': 'i32', | 25 'int32': 'i32', |
| 26 'int64': 'i64', | 26 'int64': 'i64', |
| 27 'uint8': 'u8', | 27 'uint8': 'u8', |
| 28 'uint16': 'u16', | 28 'uint16': 'u16', |
| 29 'uint32': 'u32', | 29 'uint32': 'u32', |
| 30 'uint64': 'u64', | 30 'uint64': 'u64', |
| 31 'float': 'f', | 31 'float': 'f', |
| 32 'double': 'd', | 32 'double': 'd', |
| 33 'string': 's', | 33 'string': 's', |
| 34 'handle': 'h', | 34 'handle': 'h', |
| 35 'handle<data_pipe_consumer>': 'h:d:c', | 35 'handle<data_pipe_consumer>': 'h:d:c', |
| 36 'handle<data_pipe_producer>': 'h:d:p', | 36 'handle<data_pipe_producer>': 'h:d:p', |
| 37 'handle<message_pipe>': 'h:m', | 37 'handle<message_pipe>': 'h:m', |
| 38 'handle<shared_buffer>': 'h:s'} | 38 'handle<shared_buffer>': 'h:s'} |
| 39 if kind.endswith('?'): | 39 if kind.endswith('?'): |
| 40 base_kind = _MapKind(kind[0:-1]) | 40 base_kind = MapKind(kind[0:-1]) |
| 41 # NOTE: This doesn't rule out enum types. Those will be detected later, when | 41 # NOTE: This doesn't rule out enum types. Those will be detected later, when |
| 42 # cross-reference is established. | 42 # cross-reference is established. |
| 43 reference_kinds = ('s', 'h', 'a', 'r', 'x') | 43 reference_kinds = ('m', 's', 'h', 'a', 'r', 'x') |
| 44 if base_kind[0] not in reference_kinds: | 44 if base_kind[0] not in reference_kinds: |
| 45 raise Exception( | 45 raise Exception( |
| 46 'A type (spec "%s") cannot be made nullable' % base_kind) | 46 'A type (spec "%s") cannot be made nullable' % base_kind) |
| 47 return '?' + base_kind | 47 return '?' + base_kind |
| 48 first_curly = kind.find('{') |
| 49 if first_curly != -1: |
| 50 # We want to parse associative arrays from left to right as much as |
| 51 # possible. So remove remove the first associative array key as the key |
| 52 # type, and pass the rest (which may be an array) to ourselves recursively. |
| 53 closing_curly = kind.find('}', first_curly) |
| 54 key = kind[first_curly+1:closing_curly] |
| 55 rest = kind[0:first_curly] + kind[closing_curly+1:] |
| 56 return 'm[' + MapKind(key) + '][' + MapKind(rest) + ']' |
| 48 if kind.endswith('[]'): | 57 if kind.endswith('[]'): |
| 49 typename = kind[0:-2] | 58 typename = kind[0:-2] |
| 50 if _FIXED_ARRAY_REGEXP.search(typename): | 59 if _FIXED_ARRAY_REGEXP.search(typename): |
| 51 raise Exception('Arrays of fixed sized arrays not supported') | 60 raise Exception('Arrays of fixed sized arrays not supported') |
| 52 return 'a:' + _MapKind(typename) | 61 return 'a:' + MapKind(typename) |
| 53 if kind.endswith(']'): | 62 if kind.endswith(']'): |
| 54 lbracket = kind.rfind('[') | 63 lbracket = kind.rfind('[') |
| 55 typename = kind[0:lbracket] | 64 typename = kind[0:lbracket] |
| 56 if typename.find('[') != -1: | 65 if typename.find('[') != -1: |
| 57 raise Exception('Fixed sized arrays of arrays not supported') | 66 raise Exception('Fixed sized arrays of arrays not supported') |
| 58 return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename) | 67 return 'a' + kind[lbracket+1:-1] + ':' + MapKind(typename) |
| 59 if kind.endswith('&'): | 68 if kind.endswith('&'): |
| 60 return 'r:' + _MapKind(kind[0:-1]) | 69 return 'r:' + MapKind(kind[0:-1]) |
| 61 if kind in map_to_kind: | 70 if kind in map_to_kind: |
| 62 return map_to_kind[kind] | 71 return map_to_kind[kind] |
| 63 return 'x:' + kind | 72 return 'x:' + kind |
| 64 | 73 |
| 65 def _AttributeListToDict(attribute_list): | 74 def _AttributeListToDict(attribute_list): |
| 66 if attribute_list is None: | 75 if attribute_list is None: |
| 67 return {} | 76 return {} |
| 68 assert isinstance(attribute_list, ast.AttributeList) | 77 assert isinstance(attribute_list, ast.AttributeList) |
| 69 # TODO(vtl): Check for duplicate keys here. | 78 # TODO(vtl): Check for duplicate keys here. |
| 70 return dict([(attribute.key, attribute.value) | 79 return dict([(attribute.key, attribute.value) |
| 71 for attribute in attribute_list]) | 80 for attribute in attribute_list]) |
| 72 | 81 |
| 73 def _EnumToDict(enum): | 82 def _EnumToDict(enum): |
| 74 def EnumValueToDict(enum_value): | 83 def EnumValueToDict(enum_value): |
| 75 assert isinstance(enum_value, ast.EnumValue) | 84 assert isinstance(enum_value, ast.EnumValue) |
| 76 return {'name': enum_value.name, | 85 return {'name': enum_value.name, |
| 77 'value': enum_value.value} | 86 'value': enum_value.value} |
| 78 | 87 |
| 79 assert isinstance(enum, ast.Enum) | 88 assert isinstance(enum, ast.Enum) |
| 80 return {'name': enum.name, | 89 return {'name': enum.name, |
| 81 'fields': map(EnumValueToDict, enum.enum_value_list)} | 90 'fields': map(EnumValueToDict, enum.enum_value_list)} |
| 82 | 91 |
| 83 def _ConstToDict(const): | 92 def _ConstToDict(const): |
| 84 assert isinstance(const, ast.Const) | 93 assert isinstance(const, ast.Const) |
| 85 return {'name': const.name, | 94 return {'name': const.name, |
| 86 'kind': _MapKind(const.typename), | 95 'kind': MapKind(const.typename), |
| 87 'value': const.value} | 96 'value': const.value} |
| 88 | 97 |
| 89 | 98 |
| 90 class _MojomBuilder(object): | 99 class _MojomBuilder(object): |
| 91 def __init__(self): | 100 def __init__(self): |
| 92 self.mojom = {} | 101 self.mojom = {} |
| 93 | 102 |
| 94 def Build(self, tree, name): | 103 def Build(self, tree, name): |
| 95 def StructToDict(struct): | 104 def StructToDict(struct): |
| 96 def StructFieldToDict(struct_field): | 105 def StructFieldToDict(struct_field): |
| 97 assert isinstance(struct_field, ast.StructField) | 106 assert isinstance(struct_field, ast.StructField) |
| 98 return {'name': struct_field.name, | 107 return {'name': struct_field.name, |
| 99 'kind': _MapKind(struct_field.typename), | 108 'kind': MapKind(struct_field.typename), |
| 100 'ordinal': struct_field.ordinal.value \ | 109 'ordinal': struct_field.ordinal.value \ |
| 101 if struct_field.ordinal else None, | 110 if struct_field.ordinal else None, |
| 102 'default': struct_field.default_value} | 111 'default': struct_field.default_value} |
| 103 | 112 |
| 104 assert isinstance(struct, ast.Struct) | 113 assert isinstance(struct, ast.Struct) |
| 105 return {'name': struct.name, | 114 return {'name': struct.name, |
| 106 'attributes': _AttributeListToDict(struct.attribute_list), | 115 'attributes': _AttributeListToDict(struct.attribute_list), |
| 107 'fields': _MapTreeForType(StructFieldToDict, struct.body, | 116 'fields': _MapTreeForType(StructFieldToDict, struct.body, |
| 108 ast.StructField), | 117 ast.StructField), |
| 109 'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum), | 118 'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum), |
| 110 'constants': _MapTreeForType(_ConstToDict, struct.body, | 119 'constants': _MapTreeForType(_ConstToDict, struct.body, |
| 111 ast.Const)} | 120 ast.Const)} |
| 112 | 121 |
| 113 def InterfaceToDict(interface): | 122 def InterfaceToDict(interface): |
| 114 def MethodToDict(method): | 123 def MethodToDict(method): |
| 115 def ParameterToDict(param): | 124 def ParameterToDict(param): |
| 116 assert isinstance(param, ast.Parameter) | 125 assert isinstance(param, ast.Parameter) |
| 117 return {'name': param.name, | 126 return {'name': param.name, |
| 118 'kind': _MapKind(param.typename), | 127 'kind': MapKind(param.typename), |
| 119 'ordinal': param.ordinal.value if param.ordinal else None} | 128 'ordinal': param.ordinal.value if param.ordinal else None} |
| 120 | 129 |
| 121 assert isinstance(method, ast.Method) | 130 assert isinstance(method, ast.Method) |
| 122 rv = {'name': method.name, | 131 rv = {'name': method.name, |
| 123 'parameters': map(ParameterToDict, method.parameter_list), | 132 'parameters': map(ParameterToDict, method.parameter_list), |
| 124 'ordinal': method.ordinal.value if method.ordinal else None} | 133 'ordinal': method.ordinal.value if method.ordinal else None} |
| 125 if method.response_parameter_list is not None: | 134 if method.response_parameter_list is not None: |
| 126 rv['response_parameters'] = map(ParameterToDict, | 135 rv['response_parameters'] = map(ParameterToDict, |
| 127 method.response_parameter_list) | 136 method.response_parameter_list) |
| 128 return rv | 137 return rv |
| (...skipping 22 matching lines...) Expand all Loading... |
| 151 _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface) | 160 _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface) |
| 152 self.mojom['enums'] = \ | 161 self.mojom['enums'] = \ |
| 153 _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum) | 162 _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum) |
| 154 self.mojom['constants'] = \ | 163 self.mojom['constants'] = \ |
| 155 _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const) | 164 _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const) |
| 156 return self.mojom | 165 return self.mojom |
| 157 | 166 |
| 158 | 167 |
| 159 def Translate(tree, name): | 168 def Translate(tree, name): |
| 160 return _MojomBuilder().Build(tree, name) | 169 return _MojomBuilder().Build(tree, name) |
| OLD | NEW |