OLD | NEW |
| (Empty) |
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 """Generates Python source files from a mojom.Module.""" | |
6 | |
7 import re | |
8 | |
9 import mojom.generate.constant_resolver as resolver | |
10 import mojom.generate.generator as generator | |
11 import mojom.generate.module as mojom | |
12 from mojom.generate.template_expander import UseJinja | |
13 | |
14 _kind_to_type = { | |
15 mojom.BOOL: '_descriptor.TYPE_BOOL', | |
16 mojom.INT8: '_descriptor.TYPE_INT8', | |
17 mojom.UINT8: '_descriptor.TYPE_UINT8', | |
18 mojom.INT16: '_descriptor.TYPE_INT16', | |
19 mojom.UINT16: '_descriptor.TYPE_UINT16', | |
20 mojom.INT32: '_descriptor.TYPE_INT32', | |
21 mojom.UINT32: '_descriptor.TYPE_UINT32', | |
22 mojom.INT64: '_descriptor.TYPE_INT64', | |
23 mojom.UINT64: '_descriptor.TYPE_UINT64', | |
24 mojom.FLOAT: '_descriptor.TYPE_FLOAT', | |
25 mojom.DOUBLE: '_descriptor.TYPE_DOUBLE', | |
26 mojom.STRING: '_descriptor.TYPE_STRING', | |
27 mojom.NULLABLE_STRING: '_descriptor.TYPE_NULLABLE_STRING', | |
28 mojom.HANDLE: '_descriptor.TYPE_HANDLE', | |
29 mojom.DCPIPE: '_descriptor.TYPE_HANDLE', | |
30 mojom.DPPIPE: '_descriptor.TYPE_HANDLE', | |
31 mojom.MSGPIPE: '_descriptor.TYPE_HANDLE', | |
32 mojom.SHAREDBUFFER: '_descriptor.TYPE_HANDLE', | |
33 mojom.NULLABLE_HANDLE: '_descriptor.TYPE_NULLABLE_HANDLE', | |
34 mojom.NULLABLE_DCPIPE: '_descriptor.TYPE_NULLABLE_HANDLE', | |
35 mojom.NULLABLE_DPPIPE: '_descriptor.TYPE_NULLABLE_HANDLE', | |
36 mojom.NULLABLE_MSGPIPE: '_descriptor.TYPE_NULLABLE_HANDLE', | |
37 mojom.NULLABLE_SHAREDBUFFER: '_descriptor.TYPE_NULLABLE_HANDLE', | |
38 } | |
39 | |
40 # int64 integers are not handled by array.array. int64/uint64 array are | |
41 # supported but storage is not optimized (ie. they are plain python list, not | |
42 # array.array) | |
43 _kind_to_typecode_for_native_array = { | |
44 mojom.INT8: 'b', | |
45 mojom.UINT8: 'B', | |
46 mojom.INT16: 'h', | |
47 mojom.UINT16: 'H', | |
48 mojom.INT32: 'i', | |
49 mojom.UINT32: 'I', | |
50 mojom.FLOAT: 'f', | |
51 mojom.DOUBLE: 'd', | |
52 } | |
53 | |
54 | |
55 def NameToComponent(name): | |
56 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> | |
57 # HTTP_Entry2_FooBar) | |
58 name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) | |
59 # insert '_' between non upper and start of upper blocks (e.g., | |
60 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) | |
61 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) | |
62 return [x.lower() for x in name.split('_')] | |
63 | |
64 def UpperCamelCase(name): | |
65 return ''.join([x.capitalize() for x in NameToComponent(name)]) | |
66 | |
67 def CamelCase(name): | |
68 uccc = UpperCamelCase(name) | |
69 return uccc[0].lower() + uccc[1:] | |
70 | |
71 def ConstantStyle(name): | |
72 components = NameToComponent(name) | |
73 if components[0] == 'k': | |
74 components = components[1:] | |
75 return '_'.join([x.upper() for x in components]) | |
76 | |
77 def FieldStyle(name): | |
78 components = NameToComponent(name) | |
79 return '_'.join([x.lower() for x in components]) | |
80 | |
81 def GetNameForElement(element): | |
82 if (mojom.IsEnumKind(element) or mojom.IsInterfaceKind(element) or | |
83 mojom.IsStructKind(element) or mojom.IsUnionKind(element) or | |
84 isinstance(element, mojom.Method)): | |
85 return UpperCamelCase(element.name) | |
86 if isinstance(element, mojom.EnumValue): | |
87 return (GetNameForElement(element.enum) + '.' + | |
88 ConstantStyle(element.name)) | |
89 if isinstance(element, (mojom.NamedValue, | |
90 mojom.Constant)): | |
91 return ConstantStyle(element.name) | |
92 if isinstance(element, mojom.Field): | |
93 return FieldStyle(element.name) | |
94 raise Exception('Unexpected element: %s' % element) | |
95 | |
96 def ExpressionToText(token): | |
97 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | |
98 return str(token.resolved_value) | |
99 | |
100 if isinstance(token, mojom.BuiltinValue): | |
101 if token.value == 'double.INFINITY' or token.value == 'float.INFINITY': | |
102 return 'float(\'inf\')'; | |
103 if (token.value == 'double.NEGATIVE_INFINITY' or | |
104 token.value == 'float.NEGATIVE_INFINITY'): | |
105 return 'float(\'-inf\')' | |
106 if token.value == 'double.NAN' or token.value == 'float.NAN': | |
107 return 'float(\'nan\')'; | |
108 | |
109 if token in ['true', 'false']: | |
110 return str(token == 'true') | |
111 | |
112 return token | |
113 | |
114 def GetFullyQualifiedName(kind): | |
115 name = [] | |
116 if kind.imported_from: | |
117 name.append(kind.imported_from['python_module']) | |
118 name.append(GetNameForElement(kind)) | |
119 return '.'.join(name) | |
120 | |
121 def GetFieldType(kind, field=None): | |
122 if mojom.IsArrayKind(kind): | |
123 arguments = [] | |
124 if kind.kind in _kind_to_typecode_for_native_array: | |
125 arguments.append('%r' % _kind_to_typecode_for_native_array[kind.kind]) | |
126 elif kind.kind != mojom.BOOL: | |
127 arguments.append(GetFieldType(kind.kind)) | |
128 if mojom.IsNullableKind(kind): | |
129 arguments.append('nullable=True') | |
130 if kind.length is not None: | |
131 arguments.append('length=%d' % kind.length) | |
132 array_type = 'GenericArrayType' | |
133 if kind.kind == mojom.BOOL: | |
134 array_type = 'BooleanArrayType' | |
135 elif kind.kind in _kind_to_typecode_for_native_array: | |
136 array_type = 'NativeArrayType' | |
137 return '_descriptor.%s(%s)' % (array_type, ', '.join(arguments)) | |
138 | |
139 if mojom.IsMapKind(kind): | |
140 arguments = [ | |
141 GetFieldType(kind.key_kind), | |
142 GetFieldType(kind.value_kind), | |
143 ] | |
144 if mojom.IsNullableKind(kind): | |
145 arguments.append('nullable=True') | |
146 return '_descriptor.MapType(%s)' % ', '.join(arguments) | |
147 | |
148 if mojom.IsUnionKind(kind): | |
149 arguments = [ 'lambda: %s' % GetFullyQualifiedName(kind) ] | |
150 if mojom.IsNullableKind(kind): | |
151 arguments.append('nullable=True') | |
152 return '_descriptor.UnionType(%s)' % ', '.join(arguments) | |
153 | |
154 if mojom.IsStructKind(kind): | |
155 arguments = [ 'lambda: %s' % GetFullyQualifiedName(kind) ] | |
156 if mojom.IsNullableKind(kind): | |
157 arguments.append('nullable=True') | |
158 return '_descriptor.StructType(%s)' % ', '.join(arguments) | |
159 | |
160 if mojom.IsEnumKind(kind): | |
161 return GetFieldType(mojom.INT32) | |
162 | |
163 if mojom.IsInterfaceKind(kind): | |
164 arguments = [ 'lambda: %s' % GetFullyQualifiedName(kind) ] | |
165 if mojom.IsNullableKind(kind): | |
166 arguments.append('nullable=True') | |
167 return '_descriptor.InterfaceType(%s)' % ', '.join(arguments) | |
168 | |
169 if mojom.IsInterfaceRequestKind(kind): | |
170 arguments = [] | |
171 if mojom.IsNullableKind(kind): | |
172 arguments.append('nullable=True') | |
173 return '_descriptor.InterfaceRequestType(%s)' % ', '.join(arguments) | |
174 | |
175 return _kind_to_type[kind] | |
176 | |
177 def GetFieldDescriptor(field, index, min_version, union_field=False): | |
178 class_name = 'SingleFieldGroup' | |
179 if field.kind == mojom.BOOL and not union_field: | |
180 class_name = 'FieldDescriptor' | |
181 arguments = [ '%r' % GetNameForElement(field) ] | |
182 arguments.append(GetFieldType(field.kind, field)) | |
183 arguments.append(str(index)) | |
184 arguments.append(str(min_version)) | |
185 if field.default: | |
186 if mojom.IsStructKind(field.kind): | |
187 arguments.append('default_value=True') | |
188 else: | |
189 arguments.append('default_value=%s' % ExpressionToText(field.default)) | |
190 return '_descriptor.%s(%s)' % (class_name, ', '.join(arguments)) | |
191 | |
192 def GetStructFieldDescriptor(packed_field): | |
193 return GetFieldDescriptor( | |
194 packed_field.field, packed_field.index, packed_field.min_version) | |
195 | |
196 def GetUnionFieldDescriptor(field): | |
197 return GetFieldDescriptor(field, field.ordinal, 0, union_field=True) | |
198 | |
199 def GetFieldGroup(byte): | |
200 if byte.packed_fields[0].field.kind == mojom.BOOL: | |
201 descriptors = map(GetStructFieldDescriptor, byte.packed_fields) | |
202 return '_descriptor.BooleanGroup([%s])' % ', '.join(descriptors) | |
203 assert len(byte.packed_fields) == 1 | |
204 return GetStructFieldDescriptor(byte.packed_fields[0]) | |
205 | |
206 def MojomToPythonImport(mojom): | |
207 return mojom.replace('.mojom', '_mojom') | |
208 | |
209 class Generator(generator.Generator): | |
210 | |
211 python_filters = { | |
212 'expression_to_text': ExpressionToText, | |
213 'field_group': GetFieldGroup, | |
214 'union_field_descriptor': GetUnionFieldDescriptor, | |
215 'fully_qualified_name': GetFullyQualifiedName, | |
216 'name': GetNameForElement, | |
217 } | |
218 | |
219 @UseJinja('python_templates/module.py.tmpl', filters=python_filters) | |
220 def GeneratePythonModule(self): | |
221 return { | |
222 'enums': self.module.enums, | |
223 'imports': self.GetImports(), | |
224 'interfaces': self.GetInterfaces(), | |
225 'module': resolver.ResolveConstants(self.module, ExpressionToText), | |
226 'namespace': self.module.namespace, | |
227 'structs': self.GetStructs(), | |
228 'unions': self.GetUnions(), | |
229 } | |
230 | |
231 def GenerateFiles(self, args): | |
232 import_path = MojomToPythonImport(self.module.name) | |
233 self.Write(self.GeneratePythonModule(), | |
234 self.MatchMojomFilePath('%s.py' % import_path)) | |
235 | |
236 def GetImports(self): | |
237 for each in self.module.transitive_imports: | |
238 each['python_module'] = MojomToPythonImport(each['module_name']) | |
239 return self.module.imports | |
240 | |
241 def GetJinjaParameters(self): | |
242 return { | |
243 'lstrip_blocks': True, | |
244 'trim_blocks': True, | |
245 } | |
OLD | NEW |