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