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 |
11 import mojom.generate.module as mojom | 11 import mojom.generate.module as mojom |
12 from mojom.generate.template_expander import UseJinja | 12 from mojom.generate.template_expander import UseJinja |
13 | 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 |
14 | 40 |
15 def NameToComponent(name): | 41 def NameToComponent(name): |
16 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> | 42 # insert '_' between anything and a Title name (e.g, HTTPEntry2FooBar -> |
17 # HTTP_Entry2_FooBar) | 43 # HTTP_Entry2_FooBar) |
18 name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) | 44 name = re.sub('([^_])([A-Z][^A-Z_]+)', r'\1_\2', name) |
19 # insert '_' between non upper and start of upper blocks (e.g., | 45 # insert '_' between non upper and start of upper blocks (e.g., |
20 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) | 46 # HTTP_Entry2_FooBar -> HTTP_Entry2_Foo_Bar) |
21 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) | 47 name = re.sub('([^A-Z_])([A-Z])', r'\1_\2', name) |
22 return [x.lower() for x in name.split('_')] | 48 return [x.lower() for x in name.split('_')] |
23 | 49 |
(...skipping 17 matching lines...) Expand all Loading... |
41 if isinstance(element, mojom.EnumValue): | 67 if isinstance(element, mojom.EnumValue): |
42 return (GetNameForElement(element.enum) + '.' + | 68 return (GetNameForElement(element.enum) + '.' + |
43 ConstantStyle(element.name)) | 69 ConstantStyle(element.name)) |
44 if isinstance(element, (mojom.NamedValue, | 70 if isinstance(element, (mojom.NamedValue, |
45 mojom.Constant)): | 71 mojom.Constant)): |
46 return ConstantStyle(element.name) | 72 return ConstantStyle(element.name) |
47 raise Exception('Unexpected element: ' % element) | 73 raise Exception('Unexpected element: ' % element) |
48 | 74 |
49 def ExpressionToText(token): | 75 def ExpressionToText(token): |
50 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): | 76 if isinstance(token, (mojom.EnumValue, mojom.NamedValue)): |
51 # Both variable and enum constants are constructed like: | 77 return str(token.computed_value) |
52 # PythonModule[.Struct][.Enum].CONSTANT_NAME | |
53 name = [] | |
54 if token.imported_from: | |
55 name.append(token.imported_from['python_module']) | |
56 if token.parent_kind: | |
57 name.append(GetNameForElement(token.parent_kind)) | |
58 name.append(GetNameForElement(token)) | |
59 return '.'.join(name) | |
60 | 78 |
61 if isinstance(token, mojom.BuiltinValue): | 79 if isinstance(token, mojom.BuiltinValue): |
62 if token.value == 'double.INFINITY' or token.value == 'float.INFINITY': | 80 if token.value == 'double.INFINITY' or token.value == 'float.INFINITY': |
63 return 'float(\'inf\')'; | 81 return 'float(\'inf\')'; |
64 if (token.value == 'double.NEGATIVE_INFINITY' or | 82 if (token.value == 'double.NEGATIVE_INFINITY' or |
65 token.value == 'float.NEGATIVE_INFINITY'): | 83 token.value == 'float.NEGATIVE_INFINITY'): |
66 return 'float(\'-inf\')' | 84 return 'float(\'-inf\')' |
67 if token.value == 'double.NAN' or token.value == 'float.NAN': | 85 if token.value == 'double.NAN' or token.value == 'float.NAN': |
68 return 'float(\'nan\')'; | 86 return 'float(\'nan\')'; |
69 | 87 |
| 88 if token in ["true", "false"]: |
| 89 return str(token == "true") |
| 90 |
70 return token | 91 return token |
71 | 92 |
| 93 def GetStructClass(kind): |
| 94 name = [] |
| 95 if kind.imported_from: |
| 96 name.append(kind.imported_from['python_module']) |
| 97 name.append(GetNameForElement(kind)) |
| 98 return '.'.join(name) |
72 | 99 |
73 def ComputeConstantValues(module): | 100 def GetFieldType(kind, field=None): |
| 101 if mojom.IsAnyArrayKind(kind): |
| 102 arguments = [ GetFieldType(kind.kind) ] |
| 103 if mojom.IsNullableKind(kind): |
| 104 arguments.append("nullable=True") |
| 105 if mojom.IsFixedArrayKind(kind): |
| 106 arguments.append("length=%d" % kind.length) |
| 107 return "_descriptor.ArrayType(%s)" % ", ".join(arguments) |
| 108 |
| 109 if mojom.IsStructKind(kind): |
| 110 arguments = [ GetStructClass(kind) ] |
| 111 if mojom.IsNullableKind(kind): |
| 112 arguments.append("nullable=True") |
| 113 return "_descriptor.StructType(%s)" % ", ".join(arguments) |
| 114 |
| 115 if mojom.IsEnumKind(kind): |
| 116 return GetFieldType(mojom.INT32) |
| 117 |
| 118 return _kind_to_type.get(kind, "_descriptor.TYPE_NONE") |
| 119 |
| 120 def GetFieldDescriptor(packed_field): |
| 121 field = packed_field.field |
| 122 arguments = [ '\'%s\'' % field.name ] |
| 123 arguments.append(GetFieldType(field.kind, field)) |
| 124 arguments.append(str(packed_field.offset)) |
| 125 if field.kind == mojom.BOOL: |
| 126 arguments.append('bit_offset=%d' % packed_field.bit) |
| 127 if field.default: |
| 128 if mojom.IsStructKind(field.kind): |
| 129 arguments.append('default_value=True') |
| 130 else: |
| 131 arguments.append('default_value=%s' % ExpressionToText(field.default)) |
| 132 return '_descriptor.FieldDescriptor(%s)' % ', '.join(arguments) |
| 133 |
| 134 def ComputeStaticValues(module): |
74 in_progress = set() | 135 in_progress = set() |
75 computed = set() | 136 computed = set() |
76 | 137 |
77 def ResolveEnum(enum): | 138 def GetComputedValue(named_value): |
78 def GetComputedValue(enum_value): | 139 if isinstance(named_value, mojom.EnumValue): |
79 field = next(ifilter(lambda field: field.name == enum_value.name, | 140 field = next(ifilter(lambda field: field.name == named_value.name, |
80 enum_value.enum.fields), None) | 141 named_value.enum.fields), None) |
81 if not field: | 142 if not field: |
82 raise RuntimeError( | 143 raise RuntimeError( |
83 'Unable to get computed value for field %s of enum %s' % | 144 'Unable to get computed value for field %s of enum %s' % |
84 (enum_value.name, enum_value.enum.name)) | 145 (named_value.name, named_value.enum.name)) |
85 if field not in computed: | 146 if field not in computed: |
86 ResolveEnum(enum_value.enum) | 147 ResolveEnum(named_value.enum) |
87 return field.computed_value | 148 return field.computed_value |
| 149 elif isinstance(named_value, mojom.ConstantValue): |
| 150 ResolveConstant(named_value.constant) |
| 151 named_value.computed_value = named_value.constant.computed_value |
| 152 return named_value.computed_value |
| 153 else: |
| 154 print named_value |
88 | 155 |
| 156 def ResolveConstant(constant): |
| 157 if constant in computed: |
| 158 return |
| 159 if constant in in_progress: |
| 160 raise RuntimeError('Circular dependency for constant: %s' % constant.name) |
| 161 in_progress.add(constant) |
| 162 if isinstance(constant.value, (mojom.EnumValue, mojom.ConstantValue)): |
| 163 computed_value = GetComputedValue(constant.value) |
| 164 else: |
| 165 computed_value = ExpressionToText(constant.value) |
| 166 constant.computed_value = computed_value |
| 167 in_progress.remove(constant) |
| 168 computed.add(constant) |
| 169 |
| 170 def ResolveEnum(enum): |
89 def ResolveEnumField(enum, field, default_value): | 171 def ResolveEnumField(enum, field, default_value): |
90 if field in computed: | 172 if field in computed: |
91 return | 173 return |
92 if field in in_progress: | 174 if field in in_progress: |
93 raise RuntimeError('Circular dependency for enum: %s' % enum.name) | 175 raise RuntimeError('Circular dependency for enum: %s' % enum.name) |
94 in_progress.add(field) | 176 in_progress.add(field) |
95 if field.value: | 177 if field.value: |
96 if isinstance(field.value, mojom.EnumValue): | 178 if isinstance(field.value, mojom.EnumValue): |
97 computed_value = GetComputedValue(field.value) | 179 computed_value = GetComputedValue(field.value) |
98 elif isinstance(field.value, str): | 180 elif isinstance(field.value, str): |
99 computed_value = int(field.value, 0) | 181 computed_value = int(field.value, 0) |
100 else: | 182 else: |
101 raise RuntimeError('Unexpected value: %r' % field.value) | 183 raise RuntimeError('Unexpected value: %s' % field.value) |
102 else: | 184 else: |
103 computed_value = default_value | 185 computed_value = default_value |
104 field.computed_value = computed_value | 186 field.computed_value = computed_value |
105 in_progress.remove(field) | 187 in_progress.remove(field) |
106 computed.add(field) | 188 computed.add(field) |
107 | 189 |
108 current_value = 0 | 190 current_value = 0 |
109 for field in enum.fields: | 191 for field in enum.fields: |
110 ResolveEnumField(enum, field, current_value) | 192 ResolveEnumField(enum, field, current_value) |
111 current_value = field.computed_value + 1 | 193 current_value = field.computed_value + 1 |
112 | 194 |
| 195 for constant in module.constants: |
| 196 ResolveConstant(constant) |
| 197 |
113 for enum in module.enums: | 198 for enum in module.enums: |
114 ResolveEnum(enum) | 199 ResolveEnum(enum) |
115 | 200 |
116 for struct in module.structs: | 201 for struct in module.structs: |
| 202 for constant in struct.constants: |
| 203 ResolveConstant(constant) |
117 for enum in struct.enums: | 204 for enum in struct.enums: |
118 ResolveEnum(enum) | 205 ResolveEnum(enum) |
| 206 for field in struct.fields: |
| 207 if isinstance(field.default, (mojom.ConstantValue, mojom.EnumValue)): |
| 208 field.default.computed_value = GetComputedValue(field.default) |
119 | 209 |
120 return module | 210 return module |
121 | 211 |
122 class Generator(generator.Generator): | 212 class Generator(generator.Generator): |
123 | 213 |
124 python_filters = { | 214 python_filters = { |
125 'expression_to_text': ExpressionToText, | 215 'expression_to_text': ExpressionToText, |
| 216 'field_descriptor': GetFieldDescriptor, |
126 'name': GetNameForElement, | 217 'name': GetNameForElement, |
127 } | 218 } |
128 | 219 |
129 @UseJinja('python_templates/module.py.tmpl', filters=python_filters) | 220 @UseJinja('python_templates/module.py.tmpl', filters=python_filters) |
130 def GeneratePythonModule(self): | 221 def GeneratePythonModule(self): |
131 return { | 222 return { |
132 'imports': self.GetImports(), | 223 'imports': self.GetImports(), |
133 'enums': self.module.enums, | 224 'enums': self.module.enums, |
134 'module': ComputeConstantValues(self.module), | 225 'module': ComputeStaticValues(self.module), |
135 'structs': self.GetStructs(), | 226 'structs': self.GetStructs(), |
136 } | 227 } |
137 | 228 |
138 def GenerateFiles(self, args): | 229 def GenerateFiles(self, args): |
139 self.Write(self.GeneratePythonModule(), | 230 self.Write(self.GeneratePythonModule(), |
140 '%s.py' % self.module.name.replace('.mojom', '_mojom')) | 231 '%s.py' % self.module.name.replace('.mojom', '_mojom')) |
141 | 232 |
142 def GetImports(self): | 233 def GetImports(self): |
143 for each in self.module.imports: | 234 for each in self.module.imports: |
144 each['python_module'] = each['module_name'].replace('.mojom', '_mojom') | 235 each['python_module'] = each['module_name'].replace('.mojom', '_mojom') |
145 return self.module.imports | 236 return self.module.imports |
146 | 237 |
147 def GetJinjaParameters(self): | 238 def GetJinjaParameters(self): |
148 return { | 239 return { |
149 'lstrip_blocks': True, | 240 'lstrip_blocks': True, |
150 'trim_blocks': True, | 241 'trim_blocks': True, |
151 } | 242 } |
OLD | NEW |