| OLD | NEW |
| (Empty) | |
| 1 # Copyright (c) 2012 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 from code import Code |
| 6 from model import PropertyType, Type |
| 7 import cpp_util |
| 8 import schema_util |
| 9 |
| 10 class HGenerator(object): |
| 11 """A .h generator for a namespace. |
| 12 """ |
| 13 def __init__(self, namespace, cpp_type_generator): |
| 14 self._type_helper = cpp_type_generator |
| 15 self._namespace = namespace |
| 16 self._target_namespace = ( |
| 17 self._type_helper.GetCppNamespaceName(self._namespace)) |
| 18 |
| 19 def Generate(self): |
| 20 """Generates a Code object with the .h for a single namespace. |
| 21 """ |
| 22 c = Code() |
| 23 (c.Append(cpp_util.CHROMIUM_LICENSE) |
| 24 .Append() |
| 25 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) |
| 26 .Append() |
| 27 ) |
| 28 |
| 29 ifndef_name = cpp_util.GenerateIfndefName(self._namespace.source_file_dir, |
| 30 self._target_namespace) |
| 31 (c.Append('#ifndef %s' % ifndef_name) |
| 32 .Append('#define %s' % ifndef_name) |
| 33 .Append() |
| 34 .Append('#include <map>') |
| 35 .Append('#include <string>') |
| 36 .Append('#include <vector>') |
| 37 .Append() |
| 38 .Append('#include "base/basictypes.h"') |
| 39 .Append('#include "base/logging.h"') |
| 40 .Append('#include "base/memory/linked_ptr.h"') |
| 41 .Append('#include "base/memory/scoped_ptr.h"') |
| 42 .Append('#include "base/values.h"') |
| 43 .Cblock(self._type_helper.GenerateIncludes()) |
| 44 .Append() |
| 45 ) |
| 46 |
| 47 c.Concat(self._type_helper.GetRootNamespaceStart()) |
| 48 # TODO(calamity): These forward declarations should be #includes to allow |
| 49 # $ref types from other files to be used as required params. This requires |
| 50 # some detangling of windows and tabs which will currently lead to circular |
| 51 # #includes. |
| 52 forward_declarations = ( |
| 53 self._type_helper.GenerateForwardDeclarations()) |
| 54 if not forward_declarations.IsEmpty(): |
| 55 (c.Append() |
| 56 .Cblock(forward_declarations) |
| 57 ) |
| 58 |
| 59 c.Concat(self._type_helper.GetNamespaceStart()) |
| 60 c.Append() |
| 61 if self._namespace.properties: |
| 62 (c.Append('//') |
| 63 .Append('// Properties') |
| 64 .Append('//') |
| 65 .Append() |
| 66 ) |
| 67 for property in self._namespace.properties.values(): |
| 68 property_code = self._type_helper.GeneratePropertyValues( |
| 69 property, |
| 70 'extern const %(type)s %(name)s;') |
| 71 if property_code: |
| 72 c.Cblock(property_code) |
| 73 if self._namespace.types: |
| 74 (c.Append('//') |
| 75 .Append('// Types') |
| 76 .Append('//') |
| 77 .Append() |
| 78 .Cblock(self._GenerateTypes(self._FieldDependencyOrder(), |
| 79 is_toplevel=True, |
| 80 generate_typedefs=True)) |
| 81 ) |
| 82 if self._namespace.functions: |
| 83 (c.Append('//') |
| 84 .Append('// Functions') |
| 85 .Append('//') |
| 86 .Append() |
| 87 ) |
| 88 for function in self._namespace.functions.values(): |
| 89 c.Cblock(self._GenerateFunction(function)) |
| 90 if self._namespace.events: |
| 91 (c.Append('//') |
| 92 .Append('// Events') |
| 93 .Append('//') |
| 94 .Append() |
| 95 ) |
| 96 for event in self._namespace.events.values(): |
| 97 c.Cblock(self._GenerateEvent(event)) |
| 98 (c.Concat(self._type_helper.GetNamespaceEnd()) |
| 99 .Cblock(self._type_helper.GetRootNamespaceEnd()) |
| 100 .Append('#endif // %s' % ifndef_name) |
| 101 .Append() |
| 102 ) |
| 103 return c |
| 104 |
| 105 def _FieldDependencyOrder(self): |
| 106 """Generates the list of types in the current namespace in an order in which |
| 107 depended-upon types appear before types which depend on them. |
| 108 """ |
| 109 dependency_order = [] |
| 110 |
| 111 def ExpandType(path, type_): |
| 112 if type_ in path: |
| 113 raise ValueError("Illegal circular dependency via cycle " + |
| 114 ", ".join(map(lambda x: x.name, path + [type_]))) |
| 115 for prop in type_.properties.values(): |
| 116 if (prop.type_ == PropertyType.REF and |
| 117 schema_util.GetNamespace(prop.ref_type) == self._namespace.name): |
| 118 ExpandType(path + [type_], self._namespace.types[prop.ref_type]) |
| 119 if not type_ in dependency_order: |
| 120 dependency_order.append(type_) |
| 121 |
| 122 for type_ in self._namespace.types.values(): |
| 123 ExpandType([], type_) |
| 124 return dependency_order |
| 125 |
| 126 def _GenerateEnumDeclaration(self, enum_name, type_): |
| 127 """Generate the declaration of a C++ enum. |
| 128 """ |
| 129 c = Code() |
| 130 c.Sblock('enum %s {' % enum_name) |
| 131 c.Append(self._type_helper.GetEnumNoneValue(type_) + ',') |
| 132 for value in type_.enum_values: |
| 133 c.Append(self._type_helper.GetEnumValue(type_, value) + ',') |
| 134 return c.Eblock('};') |
| 135 |
| 136 def _GenerateFields(self, props): |
| 137 """Generates the field declarations when declaring a type. |
| 138 """ |
| 139 c = Code() |
| 140 needs_blank_line = False |
| 141 for prop in props: |
| 142 if needs_blank_line: |
| 143 c.Append() |
| 144 needs_blank_line = True |
| 145 if prop.description: |
| 146 c.Comment(prop.description) |
| 147 # ANY is a base::Value which is abstract and cannot be a direct member, so |
| 148 # we always need to wrap it in a scoped_ptr. |
| 149 is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY |
| 150 (c.Append('%s %s;' % ( |
| 151 self._type_helper.GetCppType(prop.type_, is_ptr=is_ptr), |
| 152 prop.unix_name)) |
| 153 ) |
| 154 return c |
| 155 |
| 156 def _GenerateType(self, type_, is_toplevel=False, generate_typedefs=False): |
| 157 """Generates a struct for |type_|. |
| 158 |
| 159 |is_toplevel| implies that the type was declared in the "types" field |
| 160 of an API schema. This determines the correct function |
| 161 modifier(s). |
| 162 |generate_typedefs| controls whether primitive types should be generated as |
| 163 a typedef. This may not always be desired. If false, |
| 164 primitive types are ignored. |
| 165 """ |
| 166 classname = cpp_util.Classname(schema_util.StripNamespace(type_.name)) |
| 167 c = Code() |
| 168 |
| 169 if type_.functions: |
| 170 # Wrap functions within types in the type's namespace. |
| 171 (c.Append('namespace %s {' % classname) |
| 172 .Append() |
| 173 ) |
| 174 for function in type_.functions.values(): |
| 175 c.Cblock(self._GenerateFunction(function)) |
| 176 c.Append('} // namespace %s' % classname) |
| 177 elif type_.property_type == PropertyType.ARRAY: |
| 178 if generate_typedefs and type_.description: |
| 179 c.Comment(type_.description) |
| 180 c.Cblock(self._GenerateType(type_.item_type)) |
| 181 if generate_typedefs: |
| 182 (c.Append('typedef std::vector<%s > %s;' % ( |
| 183 self._type_helper.GetCppType(type_.item_type), |
| 184 classname)) |
| 185 ) |
| 186 elif type_.property_type == PropertyType.STRING: |
| 187 if generate_typedefs: |
| 188 if type_.description: |
| 189 c.Comment(type_.description) |
| 190 c.Append('typedef std::string %(classname)s;') |
| 191 elif type_.property_type == PropertyType.ENUM: |
| 192 if type_.description: |
| 193 c.Comment(type_.description) |
| 194 c.Sblock('enum %(classname)s {') |
| 195 c.Append('%s,' % self._type_helper.GetEnumNoneValue(type_)) |
| 196 for value in type_.enum_values: |
| 197 c.Append('%s,' % self._type_helper.GetEnumValue(type_, value)) |
| 198 # Top level enums are in a namespace scope so the methods shouldn't be |
| 199 # static. On the other hand, those declared inline (e.g. in an object) do. |
| 200 maybe_static = '' if is_toplevel else 'static ' |
| 201 (c.Eblock('};') |
| 202 .Append() |
| 203 .Append('%sstd::string ToString(%s as_enum);' % |
| 204 (maybe_static, classname)) |
| 205 .Append('%s%s Parse%s(const std::string& as_string);' % |
| 206 (maybe_static, classname, classname)) |
| 207 ) |
| 208 elif type_.property_type == PropertyType.OBJECT: |
| 209 if type_.description: |
| 210 c.Comment(type_.description) |
| 211 (c.Sblock('struct %(classname)s {') |
| 212 .Append('%(classname)s();') |
| 213 .Append('~%(classname)s();') |
| 214 ) |
| 215 if type_.origin.from_json: |
| 216 (c.Append() |
| 217 .Comment('Populates a %s object from a base::Value. Returns' |
| 218 ' whether |out| was successfully populated.' % classname) |
| 219 .Append('static bool Populate(const base::Value& value, ' |
| 220 '%(classname)s* out);') |
| 221 ) |
| 222 if type_.origin.from_client: |
| 223 (c.Append() |
| 224 .Comment('Returns a new base::DictionaryValue representing the' |
| 225 ' serialized form of this %s object.' % classname) |
| 226 .Append('scoped_ptr<base::DictionaryValue> ToValue() const;') |
| 227 ) |
| 228 properties = type_.properties.values() |
| 229 (c.Append() |
| 230 .Cblock(self._GenerateTypes(p.type_ for p in properties)) |
| 231 .Cblock(self._GenerateFields(properties))) |
| 232 if type_.additional_properties is not None: |
| 233 # Most additionalProperties actually have type "any", which is better |
| 234 # modelled as a DictionaryValue rather than a map of string -> Value. |
| 235 if type_.additional_properties.property_type == PropertyType.ANY: |
| 236 c.Append('base::DictionaryValue additional_properties;') |
| 237 else: |
| 238 (c.Cblock(self._GenerateType(type_.additional_properties)) |
| 239 .Append('std::map<std::string, %s> additional_properties;' % |
| 240 cpp_util.PadForGenerics( |
| 241 self._type_helper.GetCppType(type_.additional_properties, |
| 242 is_in_container=True))) |
| 243 ) |
| 244 (c.Eblock() |
| 245 .Sblock(' private:') |
| 246 .Append('DISALLOW_COPY_AND_ASSIGN(%(classname)s);') |
| 247 .Eblock('};') |
| 248 ) |
| 249 elif type_.property_type == PropertyType.CHOICES: |
| 250 if type_.description: |
| 251 c.Comment(type_.description) |
| 252 # Choices are modelled with optional fields for each choice. Exactly one |
| 253 # field of the choice is guaranteed to be set by the compiler. |
| 254 (c.Sblock('struct %(classname)s {') |
| 255 .Append('%(classname)s();') |
| 256 .Append('~%(classname)s();') |
| 257 .Append()) |
| 258 c.Cblock(self._GenerateTypes(type_.choices)) |
| 259 if type_.origin.from_json: |
| 260 (c.Comment('Populates a %s object from a base::Value. Returns' |
| 261 ' whether |out| was successfully populated.' % classname) |
| 262 .Append('static bool Populate(const base::Value& value, ' |
| 263 '%(classname)s* out);') |
| 264 .Append() |
| 265 ) |
| 266 if type_.origin.from_client: |
| 267 (c.Comment('Returns a new base::Value representing the' |
| 268 ' serialized form of this %s object.' % classname) |
| 269 .Append('scoped_ptr<base::Value> ToValue() const;') |
| 270 .Append() |
| 271 ) |
| 272 c.Append('// Choices:') |
| 273 for choice_type in type_.choices: |
| 274 c.Append('%s as_%s;' % ( |
| 275 self._type_helper.GetCppType(choice_type, is_ptr=True), |
| 276 choice_type.unix_name)) |
| 277 c.Eblock('};') |
| 278 c.Substitute({'classname': classname}) |
| 279 return c |
| 280 |
| 281 def _GenerateEvent(self, event): |
| 282 """Generates the namespaces for an event. |
| 283 """ |
| 284 c = Code() |
| 285 # TODO(kalman): use event.unix_name not Classname. |
| 286 event_namespace = cpp_util.Classname(event.name) |
| 287 (c.Append('namespace %s {' % event_namespace) |
| 288 .Append() |
| 289 .Concat(self._GenerateCreateCallbackArguments(event)) |
| 290 .Eblock('} // namespace %s' % event_namespace) |
| 291 ) |
| 292 return c |
| 293 |
| 294 def _GenerateFunction(self, function): |
| 295 """Generates the namespaces and structs for a function. |
| 296 """ |
| 297 c = Code() |
| 298 # TODO(kalman): Use function.unix_name not Classname here. |
| 299 function_namespace = cpp_util.Classname(function.name) |
| 300 (c.Append('namespace %s {' % function_namespace) |
| 301 .Append() |
| 302 .Cblock(self._GenerateFunctionParams(function)) |
| 303 ) |
| 304 if function.callback: |
| 305 c.Cblock(self._GenerateFunctionResults(function.callback)) |
| 306 c.Append('} // namespace %s' % function_namespace) |
| 307 return c |
| 308 |
| 309 def _GenerateFunctionParams(self, function): |
| 310 """Generates the struct for passing parameters from JSON to a function. |
| 311 """ |
| 312 if not function.params: |
| 313 return Code() |
| 314 |
| 315 c = Code() |
| 316 (c.Sblock('struct Params {') |
| 317 .Append('static scoped_ptr<Params> Create(const base::ListValue& args);') |
| 318 .Append('~Params();') |
| 319 .Append() |
| 320 .Cblock(self._GenerateTypes(p.type_ for p in function.params)) |
| 321 .Cblock(self._GenerateFields(function.params)) |
| 322 .Eblock() |
| 323 .Sblock(' private:') |
| 324 .Append('Params();') |
| 325 .Append() |
| 326 .Append('DISALLOW_COPY_AND_ASSIGN(Params);') |
| 327 .Eblock('};') |
| 328 ) |
| 329 return c |
| 330 |
| 331 def _GenerateTypes(self, types, is_toplevel=False, generate_typedefs=False): |
| 332 """Generate the structures required by a property such as OBJECT classes |
| 333 and enums. |
| 334 """ |
| 335 c = Code() |
| 336 for type_ in types: |
| 337 c.Cblock(self._GenerateType(type_, |
| 338 is_toplevel=is_toplevel, |
| 339 generate_typedefs=generate_typedefs)) |
| 340 return c |
| 341 |
| 342 def _GenerateCreateCallbackArguments(self, function): |
| 343 """Generates functions for passing parameters to a callback. |
| 344 """ |
| 345 c = Code() |
| 346 params = function.params |
| 347 c.Cblock(self._GenerateTypes((p.type_ for p in params), is_toplevel=True)) |
| 348 |
| 349 declaration_list = [] |
| 350 for param in params: |
| 351 if param.description: |
| 352 c.Comment(param.description) |
| 353 declaration_list.append(cpp_util.GetParameterDeclaration( |
| 354 param, self._type_helper.GetCppType(param.type_))) |
| 355 c.Append('scoped_ptr<base::ListValue> Create(%s);' % |
| 356 ', '.join(declaration_list)) |
| 357 return c |
| 358 |
| 359 def _GenerateFunctionResults(self, callback): |
| 360 """Generates namespace for passing a function's result back. |
| 361 """ |
| 362 c = Code() |
| 363 (c.Append('namespace Results {') |
| 364 .Append() |
| 365 .Concat(self._GenerateCreateCallbackArguments(callback)) |
| 366 .Append('} // namespace Results') |
| 367 ) |
| 368 return c |
| OLD | NEW |