OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 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 """Code shared by the various language-specific code generators.""" | 5 """Code shared by the various language-specific code generators.""" |
6 | 6 |
7 from functools import partial | 7 from functools import partial |
8 import os.path | 8 import os.path |
9 import re | 9 import re |
10 | 10 |
11 import module as mojom | 11 import module as mojom |
12 import mojom.fileutil as fileutil | 12 import mojom.fileutil as fileutil |
13 import pack | 13 import pack |
14 | 14 |
| 15 |
15 def ExpectedArraySize(kind): | 16 def ExpectedArraySize(kind): |
16 if mojom.IsArrayKind(kind): | 17 if mojom.IsArrayKind(kind): |
17 return kind.length | 18 return kind.length |
18 return None | 19 return None |
19 | 20 |
20 def StudlyCapsToCamel(studly): | |
21 return studly[0].lower() + studly[1:] | |
22 | 21 |
23 def UnderToCamel(under): | 22 def ToCamel(identifier, lower_initial=False, dilimiter='_'): |
24 """Converts underscore_separated strings to CamelCase strings.""" | 23 """Splits |identifier| using |dilimiter|, makes the first character of each |
25 return ''.join(word.capitalize() for word in under.split('_')) | 24 word uppercased (but makes the first character of the first word lowercased |
| 25 if |lower_initial| is set to True), and joins the words. Please note that for |
| 26 each word, all the characters except the first one are untouched. |
| 27 """ |
| 28 result = ''.join( |
| 29 word[0].upper() + word[1:] for word in identifier.split(dilimiter)) |
| 30 if lower_initial: |
| 31 result = result[0].lower() + result[1:] |
| 32 return result |
| 33 |
26 | 34 |
27 def WriteFile(contents, full_path): | 35 def WriteFile(contents, full_path): |
28 # Make sure the containing directory exists. | 36 # Make sure the containing directory exists. |
29 full_dir = os.path.dirname(full_path) | 37 full_dir = os.path.dirname(full_path) |
30 fileutil.EnsureDirectoryExists(full_dir) | 38 fileutil.EnsureDirectoryExists(full_dir) |
31 | 39 |
32 # Dump the data to disk. | 40 # Dump the data to disk. |
33 with open(full_path, "w+") as f: | 41 with open(full_path, "w+") as f: |
34 f.write(contents) | 42 f.write(contents) |
35 | 43 |
| 44 |
| 45 def AddComputedData(module): |
| 46 """Adds computed data to the given module. The data is computed once and |
| 47 used repeatedly in the generation process.""" |
| 48 |
| 49 def _AddStructComputedData(exported, struct): |
| 50 struct.packed = pack.PackedStruct(struct) |
| 51 struct.bytes = pack.GetByteLayout(struct.packed) |
| 52 struct.versions = pack.GetVersionInfo(struct.packed) |
| 53 struct.exported = exported |
| 54 |
| 55 def _AddUnionComputedData(union): |
| 56 ordinal = 0 |
| 57 for field in union.fields: |
| 58 if field.ordinal is not None: |
| 59 ordinal = field.ordinal |
| 60 field.ordinal = ordinal |
| 61 ordinal += 1 |
| 62 |
| 63 def _AddInterfaceComputedData(interface): |
| 64 next_ordinal = 0 |
| 65 interface.version = 0 |
| 66 for method in interface.methods: |
| 67 if method.ordinal is None: |
| 68 method.ordinal = next_ordinal |
| 69 next_ordinal = method.ordinal + 1 |
| 70 |
| 71 if method.min_version is not None: |
| 72 interface.version = max(interface.version, method.min_version) |
| 73 |
| 74 method.param_struct = _GetStructFromMethod(method) |
| 75 interface.version = max(interface.version, |
| 76 method.param_struct.versions[-1].version) |
| 77 |
| 78 if method.response_parameters is not None: |
| 79 method.response_param_struct = _GetResponseStructFromMethod(method) |
| 80 interface.version = max( |
| 81 interface.version, |
| 82 method.response_param_struct.versions[-1].version) |
| 83 else: |
| 84 method.response_param_struct = None |
| 85 |
| 86 def _GetStructFromMethod(method): |
| 87 """Converts a method's parameters into the fields of a struct.""" |
| 88 params_class = "%s_%s_Params" % (method.interface.name, method.name) |
| 89 struct = mojom.Struct(params_class, module=method.interface.module) |
| 90 for param in method.parameters: |
| 91 struct.AddField(param.name, param.kind, param.ordinal, |
| 92 attributes=param.attributes) |
| 93 _AddStructComputedData(False, struct) |
| 94 return struct |
| 95 |
| 96 def _GetResponseStructFromMethod(method): |
| 97 """Converts a method's response_parameters into the fields of a struct.""" |
| 98 params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name) |
| 99 struct = mojom.Struct(params_class, module=method.interface.module) |
| 100 for param in method.response_parameters: |
| 101 struct.AddField(param.name, param.kind, param.ordinal, |
| 102 attributes=param.attributes) |
| 103 _AddStructComputedData(False, struct) |
| 104 return struct |
| 105 |
| 106 for struct in module.structs: |
| 107 _AddStructComputedData(True, struct) |
| 108 for union in module.unions: |
| 109 _AddUnionComputedData(union) |
| 110 for interface in module.interfaces: |
| 111 _AddInterfaceComputedData(interface) |
| 112 |
| 113 |
36 class Generator(object): | 114 class Generator(object): |
37 # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all | 115 # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all |
38 # files to stdout. | 116 # files to stdout. |
39 def __init__(self, module, output_dir=None, typemap=None, variant=None, | 117 def __init__(self, module, output_dir=None, typemap=None, variant=None, |
40 bytecode_path=None, for_blink=False, use_once_callback=False, | 118 bytecode_path=None, for_blink=False, use_once_callback=False, |
41 use_new_js_bindings=False, export_attribute=None, | 119 use_new_js_bindings=False, export_attribute=None, |
42 export_header=None, generate_non_variant_code=False): | 120 export_header=None, generate_non_variant_code=False): |
43 self.module = module | 121 self.module = module |
44 self.output_dir = output_dir | 122 self.output_dir = output_dir |
45 self.typemap = typemap or {} | 123 self.typemap = typemap or {} |
46 self.variant = variant | 124 self.variant = variant |
47 self.bytecode_path = bytecode_path | 125 self.bytecode_path = bytecode_path |
48 self.for_blink = for_blink | 126 self.for_blink = for_blink |
49 self.use_once_callback = use_once_callback | 127 self.use_once_callback = use_once_callback |
50 self.use_new_js_bindings = use_new_js_bindings | 128 self.use_new_js_bindings = use_new_js_bindings |
51 self.export_attribute = export_attribute | 129 self.export_attribute = export_attribute |
52 self.export_header = export_header | 130 self.export_header = export_header |
53 self.generate_non_variant_code = generate_non_variant_code | 131 self.generate_non_variant_code = generate_non_variant_code |
54 | 132 |
55 def GetStructsFromMethods(self): | |
56 result = [] | |
57 for interface in self.module.interfaces: | |
58 for method in interface.methods: | |
59 result.append(self._GetStructFromMethod(method)) | |
60 if method.response_parameters != None: | |
61 result.append(self._GetResponseStructFromMethod(method)) | |
62 return result | |
63 | |
64 def GetStructs(self): | |
65 return map(partial(self._AddStructComputedData, True), self.module.structs) | |
66 | |
67 def GetUnions(self): | |
68 return map(self._AddUnionComputedData, self.module.unions) | |
69 | |
70 def GetInterfaces(self): | |
71 return map(self._AddInterfaceComputedData, self.module.interfaces) | |
72 | |
73 # Prepend the filename with a directory that matches the directory of the | 133 # Prepend the filename with a directory that matches the directory of the |
74 # original .mojom file, relative to the import root. | 134 # original .mojom file, relative to the import root. |
75 def MatchMojomFilePath(self, filename): | 135 def MatchMojomFilePath(self, filename): |
76 return os.path.join(os.path.dirname(self.module.path), filename) | 136 return os.path.join(os.path.dirname(self.module.path), filename) |
77 | 137 |
78 def Write(self, contents, filename): | 138 def Write(self, contents, filename): |
79 if self.output_dir is None: | 139 if self.output_dir is None: |
80 print contents | 140 print contents |
81 return | 141 return |
82 full_path = os.path.join(self.output_dir, filename) | 142 full_path = os.path.join(self.output_dir, filename) |
83 WriteFile(contents, full_path) | 143 WriteFile(contents, full_path) |
84 | 144 |
85 def GenerateFiles(self, args): | 145 def GenerateFiles(self, args): |
86 raise NotImplementedError("Subclasses must override/implement this method") | 146 raise NotImplementedError("Subclasses must override/implement this method") |
87 | 147 |
88 def GetJinjaParameters(self): | 148 def GetJinjaParameters(self): |
89 """Returns default constructor parameters for the jinja environment.""" | 149 """Returns default constructor parameters for the jinja environment.""" |
90 return {} | 150 return {} |
91 | 151 |
92 def GetGlobals(self): | 152 def GetGlobals(self): |
93 """Returns global mappings for the template generation.""" | 153 """Returns global mappings for the template generation.""" |
94 return {} | 154 return {} |
95 | 155 |
96 def _AddStructComputedData(self, exported, struct): | |
97 """Adds computed data to the given struct. The data is computed once and | |
98 used repeatedly in the generation process.""" | |
99 struct.packed = pack.PackedStruct(struct) | |
100 struct.bytes = pack.GetByteLayout(struct.packed) | |
101 struct.versions = pack.GetVersionInfo(struct.packed) | |
102 struct.exported = exported | |
103 return struct | |
104 | |
105 def _AddUnionComputedData(self, union): | |
106 """Adds computed data to the given union. The data is computed once and | |
107 used repeatedly in the generation process.""" | |
108 ordinal = 0 | |
109 for field in union.fields: | |
110 if field.ordinal is not None: | |
111 ordinal = field.ordinal | |
112 field.ordinal = ordinal | |
113 ordinal += 1 | |
114 return union | |
115 | |
116 def _AddInterfaceComputedData(self, interface): | |
117 """Adds computed data to the given interface. The data is computed once and | |
118 used repeatedly in the generation process.""" | |
119 interface.version = 0 | |
120 for method in interface.methods: | |
121 if method.min_version is not None: | |
122 interface.version = max(interface.version, method.min_version) | |
123 | |
124 method.param_struct = self._GetStructFromMethod(method) | |
125 interface.version = max(interface.version, | |
126 method.param_struct.versions[-1].version) | |
127 | |
128 if method.response_parameters is not None: | |
129 method.response_param_struct = self._GetResponseStructFromMethod(method) | |
130 interface.version = max( | |
131 interface.version, | |
132 method.response_param_struct.versions[-1].version) | |
133 else: | |
134 method.response_param_struct = None | |
135 return interface | |
136 | |
137 def _GetStructFromMethod(self, method): | |
138 """Converts a method's parameters into the fields of a struct.""" | |
139 params_class = "%s_%s_Params" % (method.interface.name, method.name) | |
140 struct = mojom.Struct(params_class, module=method.interface.module) | |
141 for param in method.parameters: | |
142 struct.AddField(param.name, param.kind, param.ordinal, | |
143 attributes=param.attributes) | |
144 return self._AddStructComputedData(False, struct) | |
145 | |
146 def _GetResponseStructFromMethod(self, method): | |
147 """Converts a method's response_parameters into the fields of a struct.""" | |
148 params_class = "%s_%s_ResponseParams" % (method.interface.name, method.name) | |
149 struct = mojom.Struct(params_class, module=method.interface.module) | |
150 for param in method.response_parameters: | |
151 struct.AddField(param.name, param.kind, param.ordinal, | |
152 attributes=param.attributes) | |
153 return self._AddStructComputedData(False, struct) | |
OLD | NEW |