Chromium Code Reviews| 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 """Generates Python source files from a mojom.Module.""" | 5 """Generates Python source files from a mojom.Module.""" |
| 6 | 6 |
| 7 import re | 7 import re |
| 8 from itertools import ifilter | 8 from itertools import ifilter |
| 9 | 9 |
| 10 import mojom.generate.generator as generator | 10 import mojom.generate.generator as generator |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 33 mojom.NULLABLE_HANDLE: "_descriptor.TYPE_NULLABLE_HANDLE", | 33 mojom.NULLABLE_HANDLE: "_descriptor.TYPE_NULLABLE_HANDLE", |
| 34 mojom.NULLABLE_DCPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", | 34 mojom.NULLABLE_DCPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", |
| 35 mojom.NULLABLE_DPPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", | 35 mojom.NULLABLE_DPPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", |
| 36 mojom.NULLABLE_MSGPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", | 36 mojom.NULLABLE_MSGPIPE: "_descriptor.TYPE_NULLABLE_HANDLE", |
| 37 mojom.NULLABLE_SHAREDBUFFER: "_descriptor.TYPE_NULLABLE_HANDLE", | 37 mojom.NULLABLE_SHAREDBUFFER: "_descriptor.TYPE_NULLABLE_HANDLE", |
| 38 } | 38 } |
| 39 | 39 |
| 40 # int64 integers are not handled by array.array. int64/uint64 array are | 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 | 41 # supported but storage is not optimized (ie. they are plain python list, not |
| 42 # array.array) | 42 # array.array) |
| 43 _kind_to_typecode = { | 43 _kind_to_typecode_for_array = { |
|
sdefresne
2014/09/15 08:46:54
nit: _kind_to_typecode_for_native_array
qsr
2014/09/15 11:01:53
Done.
| |
| 44 mojom.INT8: "'b'", | 44 mojom.INT8: "b", |
| 45 mojom.UINT8: "'B'", | 45 mojom.UINT8: "B", |
| 46 mojom.INT16: "'h'", | 46 mojom.INT16: "h", |
| 47 mojom.UINT16: "'H'", | 47 mojom.UINT16: "H", |
| 48 mojom.INT32: "'i'", | 48 mojom.INT32: "i", |
| 49 mojom.UINT32: "'I'", | 49 mojom.UINT32: "I", |
| 50 mojom.FLOAT: "'f'", | 50 mojom.FLOAT: "f", |
| 51 mojom.DOUBLE: "'d'", | 51 mojom.DOUBLE: "d", |
| 52 } | 52 } |
| 53 | 53 |
| 54 _kind_to_typecode = dict(_kind_to_typecode_for_array) | |
| 55 _kind_to_typecode.update({ | |
| 56 mojom.INT64: "q", | |
| 57 mojom.UINT64: "Q", | |
| 58 mojom.HANDLE: "i", | |
| 59 mojom.DCPIPE: "i", | |
| 60 mojom.DPPIPE: "i", | |
| 61 mojom.MSGPIPE: "i", | |
| 62 mojom.SHAREDBUFFER: "i", | |
| 63 mojom.NULLABLE_HANDLE: "i", | |
| 64 mojom.NULLABLE_DCPIPE: "i", | |
| 65 mojom.NULLABLE_DPPIPE: "i", | |
| 66 mojom.NULLABLE_MSGPIPE: "i", | |
| 67 mojom.NULLABLE_SHAREDBUFFER: "i", | |
| 68 }) | |
| 69 | |
| 54 | 70 |
| 55 def NameToComponent(name): | 71 def NameToComponent(name): |
| 56 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> | 72 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> |
| 57 # HTTP_Entry2_FooBar) | 73 # HTTP_Entry2_FooBar) |
| 58 name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) | 74 name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) |
| 59 # insert '_' between non upper and start of upper blocks (e.g., | 75 # insert '_' between non upper and start of upper blocks (e.g., |
| 60 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) | 76 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) |
| 61 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) | 77 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) |
| 62 return [x.lower() for x in name.split('_')] | 78 return [x.lower() for x in name.split('_')] |
| 63 | 79 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 | 122 |
| 107 def GetStructClass(kind): | 123 def GetStructClass(kind): |
| 108 name = [] | 124 name = [] |
| 109 if kind.imported_from: | 125 if kind.imported_from: |
| 110 name.append(kind.imported_from['python_module']) | 126 name.append(kind.imported_from['python_module']) |
| 111 name.append(GetNameForElement(kind)) | 127 name.append(GetNameForElement(kind)) |
| 112 return '.'.join(name) | 128 return '.'.join(name) |
| 113 | 129 |
| 114 def GetFieldType(kind, field=None): | 130 def GetFieldType(kind, field=None): |
| 115 if mojom.IsAnyArrayKind(kind): | 131 if mojom.IsAnyArrayKind(kind): |
| 116 if kind.kind in _kind_to_typecode: | 132 arguments = [] |
| 117 arguments = [ _kind_to_typecode[kind.kind] ] | 133 if kind.kind in _kind_to_typecode_for_array: |
| 118 else: | 134 arguments.append('\'%s\'' %_kind_to_typecode_for_array[kind.kind]) |
|
sdefresne
2014/09/15 08:46:54
nit: you can use '%r' instead of '\'%s\'' to get a
qsr
2014/09/15 11:01:53
Done.
| |
| 119 arguments = [ GetFieldType(kind.kind) ] | 135 elif kind.kind != mojom.BOOL: |
| 136 arguments.append(GetFieldType(kind.kind)) | |
| 120 if mojom.IsNullableKind(kind): | 137 if mojom.IsNullableKind(kind): |
| 121 arguments.append("nullable=True") | 138 arguments.append("nullable=True") |
| 122 if mojom.IsFixedArrayKind(kind): | 139 if mojom.IsFixedArrayKind(kind): |
| 123 arguments.append("length=%d" % kind.length) | 140 arguments.append("length=%d" % kind.length) |
| 124 if kind.kind in _kind_to_typecode: | 141 array_type = 'GenericArrayType' |
| 125 return "_descriptor.NativeArrayType(%s)" % ", ".join(arguments) | 142 if kind.kind == mojom.BOOL: |
| 126 else: | 143 array_type = 'BooleanArrayType' |
| 127 return "_descriptor.PointerArrayType(%s)" % ", ".join(arguments) | 144 elif kind.kind in _kind_to_typecode_for_array: |
| 145 array_type = 'NativeArrayType' | |
| 146 return "_descriptor.%s(%s)" % (array_type, ", ".join(arguments)) | |
| 128 | 147 |
| 129 if mojom.IsStructKind(kind): | 148 if mojom.IsStructKind(kind): |
| 130 arguments = [ GetStructClass(kind) ] | 149 arguments = [ GetStructClass(kind) ] |
| 131 if mojom.IsNullableKind(kind): | 150 if mojom.IsNullableKind(kind): |
| 132 arguments.append("nullable=True") | 151 arguments.append("nullable=True") |
| 133 return "_descriptor.StructType(%s)" % ", ".join(arguments) | 152 return "_descriptor.StructType(%s)" % ", ".join(arguments) |
| 134 | 153 |
| 135 if mojom.IsEnumKind(kind): | 154 if mojom.IsEnumKind(kind): |
| 136 return GetFieldType(mojom.INT32) | 155 return GetFieldType(mojom.INT32) |
| 137 | 156 |
| 138 return _kind_to_type.get(kind, "_descriptor.TYPE_NONE") | 157 return _kind_to_type.get(kind, "_descriptor.TYPE_NONE") |
| 139 | 158 |
| 159 def GetPackedFormatString(struct): | |
| 160 res = '=' | |
| 161 for byte in struct.bytes: | |
| 162 if len(byte.packed_fields) > 1: | |
| 163 res += 'B' | |
| 164 else: | |
| 165 for packed_field in byte.packed_fields: | |
| 166 kind = packed_field.field.kind | |
| 167 if mojom.IsEnumKind(kind): | |
| 168 res += 'i' | |
| 169 else: | |
| 170 res += _kind_to_typecode.get(packed_field.field.kind, 'Q') | |
| 171 if byte.is_padding: | |
| 172 res += 'x' | |
| 173 return res | |
| 174 | |
| 140 def GetFieldDescriptor(packed_field): | 175 def GetFieldDescriptor(packed_field): |
| 141 field = packed_field.field | 176 field = packed_field.field |
| 177 class_name = 'SingleFieldGroup' | |
| 178 if field.kind == mojom.BOOL: | |
| 179 class_name = 'FieldDescriptor' | |
| 142 arguments = [ '\'%s\'' % field.name ] | 180 arguments = [ '\'%s\'' % field.name ] |
| 143 arguments.append(GetFieldType(field.kind, field)) | 181 arguments.append(GetFieldType(field.kind, field)) |
| 144 arguments.append(str(packed_field.offset)) | 182 arguments.append(str(packed_field.field.ordinal)) |
| 145 if field.kind == mojom.BOOL: | |
| 146 arguments.append('bit_offset=%d' % packed_field.bit) | |
| 147 if field.default: | 183 if field.default: |
| 148 if mojom.IsStructKind(field.kind): | 184 if mojom.IsStructKind(field.kind): |
| 149 arguments.append('default_value=True') | 185 arguments.append('default_value=True') |
| 150 else: | 186 else: |
| 151 arguments.append('default_value=%s' % ExpressionToText(field.default)) | 187 arguments.append('default_value=%s' % ExpressionToText(field.default)) |
| 152 return '_descriptor.FieldDescriptor(%s)' % ', '.join(arguments) | 188 return '_descriptor.%s(%s)' % (class_name, ', '.join(arguments)) |
| 189 | |
| 190 def GetFieldGroup(byte): | |
| 191 if len(byte.packed_fields) > 1: | |
| 192 descriptors = map(GetFieldDescriptor, byte.packed_fields) | |
| 193 return '_descriptor.BooleanGroup([%s])' % ', '.join(descriptors) | |
| 194 for packed_field in byte.packed_fields: | |
| 195 return GetFieldDescriptor(packed_field) | |
|
sdefresne
2014/09/15 11:14:46
This return in a for loop is strange. Do you only
qsr
2014/09/15 11:42:00
Refactored by asserting the list has a single elem
| |
| 196 print byte | |
|
sdefresne
2014/09/15 08:46:55
Are those two lines debug? Since the last line is
qsr
2014/09/15 11:01:53
The assert False is correct, the print was just fo
sdefresne
2014/09/15 11:14:46
Oh, you mean this line should not be reached? What
qsr
2014/09/15 11:42:00
Removed, asserting the list has a single element i
| |
| 197 assert False | |
| 153 | 198 |
| 154 def ComputeStaticValues(module): | 199 def ComputeStaticValues(module): |
| 155 in_progress = set() | 200 in_progress = set() |
| 156 computed = set() | 201 computed = set() |
| 157 | 202 |
| 158 def GetComputedValue(named_value): | 203 def GetComputedValue(named_value): |
| 159 if isinstance(named_value, mojom.EnumValue): | 204 if isinstance(named_value, mojom.EnumValue): |
| 160 field = next(ifilter(lambda field: field.name == named_value.name, | 205 field = next(ifilter(lambda field: field.name == named_value.name, |
| 161 named_value.enum.fields), None) | 206 named_value.enum.fields), None) |
| 162 if not field: | 207 if not field: |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 for constant in struct.constants: | 267 for constant in struct.constants: |
| 223 ResolveConstant(constant) | 268 ResolveConstant(constant) |
| 224 for enum in struct.enums: | 269 for enum in struct.enums: |
| 225 ResolveEnum(enum) | 270 ResolveEnum(enum) |
| 226 for field in struct.fields: | 271 for field in struct.fields: |
| 227 if isinstance(field.default, (mojom.ConstantValue, mojom.EnumValue)): | 272 if isinstance(field.default, (mojom.ConstantValue, mojom.EnumValue)): |
| 228 field.default.computed_value = GetComputedValue(field.default) | 273 field.default.computed_value = GetComputedValue(field.default) |
| 229 | 274 |
| 230 return module | 275 return module |
| 231 | 276 |
| 277 _HEADER_SIZE = 8 | |
| 278 | |
| 232 class Generator(generator.Generator): | 279 class Generator(generator.Generator): |
| 233 | 280 |
| 234 python_filters = { | 281 python_filters = { |
| 235 'expression_to_text': ExpressionToText, | 282 'expression_to_text': ExpressionToText, |
| 236 'field_descriptor': GetFieldDescriptor, | 283 'field_group': GetFieldGroup, |
| 237 'name': GetNameForElement, | 284 'name': GetNameForElement, |
| 285 'packed_format_string': GetPackedFormatString, | |
| 286 'struct_size': lambda ps: ps.GetTotalSize() + _HEADER_SIZE, | |
| 238 } | 287 } |
| 239 | 288 |
| 240 @UseJinja('python_templates/module.py.tmpl', filters=python_filters) | 289 @UseJinja('python_templates/module.py.tmpl', filters=python_filters) |
| 241 def GeneratePythonModule(self): | 290 def GeneratePythonModule(self): |
| 242 return { | 291 return { |
| 243 'imports': self.GetImports(), | 292 'imports': self.GetImports(), |
| 244 'enums': self.module.enums, | 293 'enums': self.module.enums, |
| 245 'module': ComputeStaticValues(self.module), | 294 'module': ComputeStaticValues(self.module), |
| 246 'structs': self.GetStructs(), | 295 'structs': self.GetStructs(), |
| 247 } | 296 } |
| 248 | 297 |
| 249 def GenerateFiles(self, args): | 298 def GenerateFiles(self, args): |
| 250 self.Write(self.GeneratePythonModule(), | 299 self.Write(self.GeneratePythonModule(), |
| 251 '%s.py' % self.module.name.replace('.mojom', '_mojom')) | 300 '%s.py' % self.module.name.replace('.mojom', '_mojom')) |
| 252 | 301 |
| 253 def GetImports(self): | 302 def GetImports(self): |
| 254 for each in self.module.imports: | 303 for each in self.module.imports: |
| 255 each['python_module'] = each['module_name'].replace('.mojom', '_mojom') | 304 each['python_module'] = each['module_name'].replace('.mojom', '_mojom') |
| 256 return self.module.imports | 305 return self.module.imports |
| 257 | 306 |
| 258 def GetJinjaParameters(self): | 307 def GetJinjaParameters(self): |
| 259 return { | 308 return { |
| 260 'lstrip_blocks': True, | 309 'lstrip_blocks': True, |
| 261 'trim_blocks': True, | 310 'trim_blocks': True, |
| 262 } | 311 } |
| OLD | NEW |