| OLD | NEW |
| 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 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 """Generates C++ source files from a mojom.Module.""" |
| 6 |
| 5 import datetime | 7 import datetime |
| 6 import mojom | 8 import mojom |
| 7 import mojom_pack | 9 import mojom_pack |
| 8 import os | 10 import os |
| 9 import sys | 11 import sys |
| 10 | 12 |
| 11 from string import Template | 13 from string import Template |
| 12 | 14 |
| 13 # mojom_cpp_generator provides a way to generate c++ code from a mojom.Module. | 15 # mojom_cpp_generator provides a way to generate c++ code from a mojom.Module. |
| 14 # cpp = mojom_cpp_generator.CPPGenerator(module) | 16 # cpp = mojom_cpp_generator.CPPGenerator(module) |
| 15 # cpp.GenerateFiles("/tmp/g") | 17 # cpp.GenerateFiles("/tmp/g") |
| 16 def ReadTemplate(filename): | 18 def ReadTemplate(filename): |
| 19 """Reads a string.Template from |filename|.""" |
| 17 dir = os.path.dirname(__file__) | 20 dir = os.path.dirname(__file__) |
| 18 with open(dir + '/' + filename, 'r') as file: | 21 with open(dir + '/' + filename, 'r') as file: |
| 19 return Template(file.read()) | 22 return Template(file.read()) |
| 20 | 23 |
| 21 | 24 |
| 25 def AddForward(forwards, kind): |
| 26 """Adds a forward class declaration line to the |forwards| set.""" |
| 27 if isinstance(kind, mojom.Struct): |
| 28 forwards.add("class %s;" % kind.name.capitalize()) |
| 29 if isinstance(kind, mojom.Array): |
| 30 AddForward(forwards, kind.kind) |
| 31 |
| 32 |
| 33 def GetForwards(forwards): |
| 34 """Returns a string suitable for substituting into a $FORWARDS section.""" |
| 35 if len(forwards) > 0: |
| 36 return '\n'.join(sorted(forwards)) + '\n' |
| 37 return "" |
| 38 |
| 39 |
| 22 class CPPGenerator(object): | 40 class CPPGenerator(object): |
| 23 struct_template = ReadTemplate("cpp_struct.template") | 41 |
| 24 interface_template = ReadTemplate("cpp_interface.template") | 42 struct_header_template = ReadTemplate("module_struct.h") |
| 43 struct_source_template = ReadTemplate("module_struct.cc") |
| 44 interface_header_template = ReadTemplate("module_interface.h") |
| 25 field_template = Template(" $itype ${field}_;") | 45 field_template = Template(" $itype ${field}_;") |
| 26 bool_field_template = Template(" uint8_t ${field}_ : 1;") | 46 bool_field_template = Template(" uint8_t ${field}_ : 1;") |
| 27 setter_template = \ | 47 setter_template = \ |
| 28 Template(" void set_$field($stype $field) { ${field}_ = $field; }") | 48 Template(" void set_$field($stype $field) { ${field}_ = $field; }") |
| 29 getter_template = \ | 49 getter_template = \ |
| 30 Template(" $gtype $field() const { return ${field}_; }") | 50 Template(" $gtype $field() const { return ${field}_; }") |
| 31 ptr_getter_template = \ | 51 ptr_getter_template = \ |
| 32 Template(" $gtype $field() const { return ${field}_.ptr; }") | 52 Template(" $gtype $field() const { return ${field}_.ptr; }") |
| 33 pad_template = Template(" uint8_t _pad${count}_[$pad];") | 53 pad_template = Template(" uint8_t _pad${count}_[$pad];") |
| 54 HEADER_SIZE = 8 |
| 34 | 55 |
| 35 kind_to_type = { | 56 kind_to_type = { |
| 36 mojom.BOOL: "bool", | 57 mojom.BOOL: "bool", |
| 37 mojom.INT8: "int8_t", | 58 mojom.INT8: "int8_t", |
| 38 mojom.UINT8: "uint8_t", | 59 mojom.UINT8: "uint8_t", |
| 39 mojom.INT16: "int16_t", | 60 mojom.INT16: "int16_t", |
| 40 mojom.UINT16: "uint16_t", | 61 mojom.UINT16: "uint16_t", |
| 41 mojom.INT32: "int32_t", | 62 mojom.INT32: "int32_t", |
| 42 mojom.UINT32: "uint32_t", | 63 mojom.UINT32: "uint32_t", |
| 43 mojom.FLOAT: "float", | 64 mojom.FLOAT: "float", |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 elif kind.spec == 's': | 117 elif kind.spec == 's': |
| 97 itype = "mojo::internal::StringPointer" | 118 itype = "mojo::internal::StringPointer" |
| 98 else: | 119 else: |
| 99 itype = cls.kind_to_type[kind] | 120 itype = cls.kind_to_type[kind] |
| 100 return cls.field_template.substitute(field=pf.field.name, itype=itype) | 121 return cls.field_template.substitute(field=pf.field.name, itype=itype) |
| 101 | 122 |
| 102 def GetHeaderGuard(self, component): | 123 def GetHeaderGuard(self, component): |
| 103 return "MOJO_GENERATED_BINDINGS_%s_%s_H_" % \ | 124 return "MOJO_GENERATED_BINDINGS_%s_%s_H_" % \ |
| 104 (self.module.name.upper(), component.name.upper()) | 125 (self.module.name.upper(), component.name.upper()) |
| 105 | 126 |
| 106 def OpenComponentFile(self, directory, component): | 127 # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all files |
| 107 filename = "%s_%s.h" % \ | 128 # to stdout. |
| 108 (self.module.name.lower(), component.name.lower()) | 129 def __init__(self, module, header_dir, output_dir=None): |
| 109 return open(directory + '/' + filename, "w+") | 130 self.module = module |
| 131 self.header_dir = header_dir |
| 132 self.output_dir = output_dir |
| 110 | 133 |
| 111 def __init__(self, module): | 134 def WriteTemplateToFile(self, template, name, ext, **substitutions): |
| 112 self.module = module | 135 if self.output_dir is None: |
| 113 self.file = file | 136 file = sys.stdout |
| 137 else: |
| 138 filename = "%s_%s.%s" % \ |
| 139 (self.module.name.lower(), name.lower(), ext) |
| 140 file = open(os.path.join(self.output_dir, filename), "w+") |
| 141 try: |
| 142 file.write(template.substitute(substitutions)) |
| 143 finally: |
| 144 if self.output_dir is not None: |
| 145 file.close() |
| 114 | 146 |
| 115 def GenerateStruct(self, struct, file): | 147 def GenerateStructHeader(self, struct): |
| 116 fields = [] | 148 fields = [] |
| 117 setters = [] | 149 setters = [] |
| 118 getters = [] | 150 getters = [] |
| 151 forwards = set() |
| 119 | 152 |
| 120 ps = mojom_pack.PackedStruct(struct) | 153 ps = mojom_pack.PackedStruct(struct) |
| 121 pad_count = 0 | 154 pad_count = 0 |
| 122 num_fields = len(ps.packed_fields) | 155 num_fields = len(ps.packed_fields) |
| 123 for i in xrange(num_fields): | 156 for i in xrange(num_fields): |
| 124 pf = ps.packed_fields[i] | 157 pf = ps.packed_fields[i] |
| 125 fields.append(self.GetFieldLine(pf)) | 158 fields.append(self.GetFieldLine(pf)) |
| 159 AddForward(forwards, pf.field.kind) |
| 126 if i < (num_fields - 2): | 160 if i < (num_fields - 2): |
| 127 next_pf = ps.packed_fields[i+1] | 161 next_pf = ps.packed_fields[i+1] |
| 128 pad = next_pf.offset - (pf.offset + pf.size) | 162 pad = next_pf.offset - (pf.offset + pf.size) |
| 129 if pad > 0: | 163 if pad > 0: |
| 130 fields.append(self.pad_template.substitute(count=pad_count, pad=pad)) | 164 fields.append(self.pad_template.substitute(count=pad_count, pad=pad)) |
| 131 pad_count += 1 | 165 pad_count += 1 |
| 132 setters.append(self.GetSetterLine(pf)) | 166 setters.append(self.GetSetterLine(pf)) |
| 133 getters.append(self.GetGetterLine(pf)) | 167 getters.append(self.GetGetterLine(pf)) |
| 134 | 168 |
| 135 if num_fields > 0: | 169 if num_fields > 0: |
| 136 last_field = ps.packed_fields[num_fields - 1] | 170 last_field = ps.packed_fields[num_fields - 1] |
| 137 offset = last_field.offset + last_field.size | 171 offset = last_field.offset + last_field.size |
| 138 pad = mojom_pack.GetPad(offset, 8) | 172 pad = mojom_pack.GetPad(offset, 8) |
| 139 if pad > 0: | 173 if pad > 0: |
| 140 fields.append(self.pad_template.substitute(count=pad_count, pad=pad)) | 174 fields.append(self.pad_template.substitute(count=pad_count, pad=pad)) |
| 141 pad_count += 1 | 175 pad_count += 1 |
| 142 size = offset + pad | 176 size = offset + pad |
| 143 else: | 177 else: |
| 144 size = 0 | 178 size = 0 |
| 145 | 179 |
| 146 file.write(self.struct_template.substitute( | 180 self.WriteTemplateToFile(self.struct_header_template, struct.name, 'h', |
| 147 year = datetime.date.today().year, | 181 YEAR = datetime.date.today().year, |
| 148 header_guard = self.GetHeaderGuard(struct), | 182 HEADER_GUARD = self.GetHeaderGuard(struct), |
| 149 namespace = self.module.namespace, | 183 NAMESPACE = self.module.namespace, |
| 150 classname = struct.name.capitalize(), | 184 CLASS = struct.name.capitalize(), |
| 151 num_fields = len(ps.packed_fields), | 185 SIZE = size + self.HEADER_SIZE, |
| 152 size = size + 8, | 186 FORWARDS = GetForwards(forwards), |
| 153 setters = '\n'.join(setters), | 187 SETTERS = '\n'.join(setters), |
| 154 getters = '\n'.join(getters), | 188 GETTERS = '\n'.join(getters), |
| 155 fields = '\n'.join(fields))) | 189 FIELDS = '\n'.join(fields)) |
| 156 | 190 |
| 157 def GenerateInterface(self, interface, file): | 191 def GenerateStructSource(self, struct): |
| 192 header = "%s_%s.h" % (self.module.name.lower(), struct.name.lower()) |
| 193 header = os.path.join(self.header_dir, header) |
| 194 self.WriteTemplateToFile(self.struct_source_template, struct.name, 'cc', |
| 195 YEAR = datetime.date.today().year, |
| 196 NAMESPACE = self.module.namespace, |
| 197 CLASS = struct.name.capitalize(), |
| 198 NUM_FIELDS = len(struct.fields), |
| 199 HEADER = header) |
| 200 |
| 201 def GenerateInterfaceHeader(self, interface): |
| 158 cpp_methods = [] | 202 cpp_methods = [] |
| 203 forwards = set() |
| 159 for method in interface.methods: | 204 for method in interface.methods: |
| 160 cpp_method = " virtual void %s(" % method.name | 205 cpp_method = " virtual void %s(" % method.name |
| 161 first_param = True | 206 first_param = True |
| 162 for param in method.parameters: | 207 for param in method.parameters: |
| 163 if first_param == True: | 208 if first_param == True: |
| 164 first_param = False | 209 first_param = False |
| 165 else: | 210 else: |
| 166 cpp_method += ", " | 211 cpp_method += ", " |
| 212 AddForward(forwards, param.kind) |
| 167 cpp_method += "%s %s" % (self.GetConstType(param.kind), param.name) | 213 cpp_method += "%s %s" % (self.GetConstType(param.kind), param.name) |
| 168 cpp_method += ") = 0;" | 214 cpp_method += ") = 0;" |
| 169 cpp_methods.append(cpp_method) | 215 cpp_methods.append(cpp_method) |
| 170 | 216 |
| 171 file.write(self.interface_template.substitute( | 217 self.WriteTemplateToFile( |
| 172 year = datetime.date.today().year, | 218 self.interface_header_template, |
| 173 header_guard = self.GetHeaderGuard(interface), | 219 interface.name, |
| 174 namespace = self.module.namespace, | 220 'h', |
| 175 classname = interface.name.capitalize(), | 221 YEAR = datetime.date.today().year, |
| 176 methods = '\n'.join(cpp_methods))) | 222 HEADER_GUARD = self.GetHeaderGuard(interface), |
| 223 NAMESPACE = self.module.namespace, |
| 224 CLASS = interface.name.capitalize(), |
| 225 FORWARDS = GetForwards(forwards), |
| 226 METHODS = '\n'.join(cpp_methods)) |
| 177 | 227 |
| 178 # Pass |directory| to emit files to disk. Omit |directory| to echo all files | 228 def GenerateFiles(self): |
| 179 # to stdout. | |
| 180 def GenerateFiles(self, directory=None): | |
| 181 for struct in self.module.structs: | 229 for struct in self.module.structs: |
| 182 if directory is None: | 230 self.GenerateStructHeader(struct) |
| 183 self.GenerateStruct(struct, sys.stdout) | 231 self.GenerateStructSource(struct) |
| 184 else: | |
| 185 with self.OpenComponentFile(directory, struct) as file: | |
| 186 self.GenerateStruct(struct, file) | |
| 187 for interface in self.module.interfaces: | 232 for interface in self.module.interfaces: |
| 188 if directory is None: | 233 self.GenerateInterfaceHeader(interface) |
| 189 self.GenerateInterface(interface, sys.stdout) | |
| 190 else: | |
| 191 with self.OpenComponentFile(directory, interface) as file: | |
| 192 self.GenerateInterface(interface, file) | |
| OLD | NEW |