Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: tools/json_schema_compiler/cc_generator.py

Issue 11827026: Overhaul JSON Schema Compiler to support a number of features required to (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/json_schema_compiler/api_gen_util.gyp ('k') | tools/json_schema_compiler/code.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 from code import Code 5 from code import Code
6 from model import PropertyType 6 from model import PropertyType, Type
7 import any_helper
8 import cpp_util 7 import cpp_util
9 import model 8 import model
10 import schema_util 9 import schema_util
11 import sys 10 import sys
12 import util_cc_helper 11 import util_cc_helper
13 12
14 class CCGenerator(object): 13 class CCGenerator(object):
15 """A .cc generator for a namespace. 14 """A .cc generator for a namespace.
16 """ 15 """
17 def __init__(self, namespace, cpp_type_generator): 16 def __init__(self, namespace, cpp_type_generator):
18 self._cpp_type_generator = cpp_type_generator 17 self._type_helper = cpp_type_generator
19 self._namespace = namespace 18 self._namespace = namespace
20 self._target_namespace = ( 19 self._target_namespace = (
21 self._cpp_type_generator.GetCppNamespaceName(self._namespace)) 20 self._type_helper.GetCppNamespaceName(self._namespace))
22 self._util_cc_helper = ( 21 self._util_cc_helper = (
23 util_cc_helper.UtilCCHelper(self._cpp_type_generator)) 22 util_cc_helper.UtilCCHelper(self._type_helper))
24 self._any_helper = any_helper.AnyHelper()
25 23
26 def Generate(self): 24 def Generate(self):
27 """Generates a Code object with the .cc for a single namespace. 25 """Generates a Code object with the .cc for a single namespace.
28 """ 26 """
29 c = Code() 27 c = Code()
30 (c.Append(cpp_util.CHROMIUM_LICENSE) 28 (c.Append(cpp_util.CHROMIUM_LICENSE)
31 .Append() 29 .Append()
32 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) 30 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file)
33 .Append() 31 .Append()
34 .Append(self._util_cc_helper.GetIncludePath()) 32 .Append(self._util_cc_helper.GetIncludePath())
35 .Append('#include "%s/%s.h"' % 33 .Append('#include "%s/%s.h"' %
36 (self._namespace.source_file_dir, self._namespace.unix_name)) 34 (self._namespace.source_file_dir, self._namespace.unix_name))
37 ) 35 .Append('#include "base/logging.h"')
38 includes = self._cpp_type_generator.GenerateIncludes() 36 .Cblock(self._type_helper.GenerateIncludes())
39 if not includes.IsEmpty(): 37 .Concat(self._type_helper.GetRootNamespaceStart())
40 (c.Concat(includes) 38 .Cblock(self._type_helper.GetNamespaceStart())
41 .Append()
42 )
43
44 (c.Append()
45 .Concat(self._cpp_type_generator.GetRootNamespaceStart())
46 .Concat(self._cpp_type_generator.GetNamespaceStart())
47 .Append()
48 ) 39 )
49 if self._namespace.properties: 40 if self._namespace.properties:
50 (c.Append('//') 41 (c.Append('//')
51 .Append('// Properties') 42 .Append('// Properties')
52 .Append('//') 43 .Append('//')
53 .Append() 44 .Append()
54 ) 45 )
55 for property in self._namespace.properties.values(): 46 for property in self._namespace.properties.values():
56 property_code = self._cpp_type_generator.GeneratePropertyValues( 47 property_code = self._type_helper.GeneratePropertyValues(
57 property, 48 property,
58 'const %(type)s %(name)s = %(value)s;', 49 'const %(type)s %(name)s = %(value)s;',
59 nodoc=True) 50 nodoc=True)
60 if property_code: 51 if property_code:
61 c.Concat(property_code).Append() 52 c.Cblock(property_code)
62 if self._namespace.types: 53 if self._namespace.types:
63 (c.Append('//') 54 (c.Append('//')
64 .Append('// Types') 55 .Append('// Types')
65 .Append('//') 56 .Append('//')
66 .Append() 57 .Append()
67 ) 58 .Cblock(self._GenerateTypes(None, self._namespace.types.values()))
68 for type_ in self._namespace.types.values():
69 (c.Concat(self._GenerateType(
70 schema_util.StripSchemaNamespace(type_.name), type_)).Append()
71 ) 59 )
72 if self._namespace.functions: 60 if self._namespace.functions:
73 (c.Append('//') 61 (c.Append('//')
74 .Append('// Functions') 62 .Append('// Functions')
75 .Append('//') 63 .Append('//')
76 .Append() 64 .Append()
77 ) 65 )
78 for function in self._namespace.functions.values(): 66 for function in self._namespace.functions.values():
79 (c.Concat(self._GenerateFunction( 67 c.Cblock(self._GenerateFunction(function))
80 cpp_util.Classname(function.name), function))
81 .Append()
82 )
83 if self._namespace.events: 68 if self._namespace.events:
84 (c.Append('//') 69 (c.Append('//')
85 .Append('// Events') 70 .Append('// Events')
86 .Append('//') 71 .Append('//')
87 .Append() 72 .Append()
88 ) 73 )
89 for event in self._namespace.events.values(): 74 for event in self._namespace.events.values():
90 (c.Concat(self._GenerateCreateCallbackArguments( 75 c.Cblock(self._GenerateEvent(event))
91 cpp_util.Classname(event.name), event, generate_to_json=True)) 76 (c.Concat(self._type_helper.GetNamespaceEnd())
92 .Append() 77 .Cblock(self._type_helper.GetRootNamespaceEnd())
93 )
94 (c.Concat(self._cpp_type_generator.GetNamespaceEnd())
95 .Concat(self._cpp_type_generator.GetRootNamespaceEnd())
96 .Append()
97 ) 78 )
98 return c 79 return c
99 80
100 def _GenerateType(self, cpp_namespace, type_): 81 def _GenerateType(self, cpp_namespace, type_):
101 """Generates the function definitions for a type. 82 """Generates the function definitions for a type.
102 """ 83 """
103 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) 84 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
104 c = Code() 85 c = Code()
105 86
106 if type_.functions: 87 if type_.functions:
88 # Wrap functions within types in the type's namespace.
89 (c.Append('namespace %s {' % classname)
90 .Append())
107 for function in type_.functions.values(): 91 for function in type_.functions.values():
108 (c.Concat( 92 c.Cblock(self._GenerateFunction(function))
109 self._GenerateFunction( 93 c.Append('} // namespace %s' % classname)
110 cpp_namespace + '::' + cpp_util.Classname(function.name), 94 elif type_.property_type == PropertyType.ARRAY:
111 function)) 95 c.Cblock(self._GenerateType(cpp_namespace, type_.item_type))
112 .Append()) 96 elif (type_.property_type == PropertyType.OBJECT or
113 elif type_.type_ == PropertyType.OBJECT: 97 type_.property_type == PropertyType.CHOICES):
114 (c.Concat(self._GeneratePropertyFunctions( 98 if cpp_namespace is None:
115 cpp_namespace, type_.properties.values())) 99 classname_in_namespace = classname
116 .Sblock('%(namespace)s::%(classname)s()') 100 else:
117 .Concat(self._GenerateInitializersAndBody(type_)) 101 classname_in_namespace = '%s::%s' % (cpp_namespace, classname)
118 .Eblock('%(namespace)s::~%(classname)s() {}') 102
119 .Append()) 103 if type_.property_type == PropertyType.OBJECT:
120 if type_.from_json: 104 c.Cblock(self._GeneratePropertyFunctions(classname_in_namespace,
121 (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)) 105 type_.properties.values()))
122 .Append()) 106 else:
123 if type_.from_client: 107 c.Cblock(self._GenerateTypes(classname_in_namespace, type_.choices))
124 (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)) 108
125 .Append()) 109 (c.Append('%s::%s()' % (classname_in_namespace, classname))
126 elif self._cpp_type_generator.IsEnumOrEnumRef(type_): 110 .Cblock(self._GenerateInitializersAndBody(type_))
127 (c.Concat(self._GenerateCreateEnumTypeValue(cpp_namespace, type_)) 111 .Append('%s::~%s() {}' % (classname_in_namespace, classname))
128 .Append() 112 .Append()
129 .Concat(self._GenerateEnumFromString(cpp_namespace, type_)) 113 )
130 .Append() 114 if type_.origin.from_json:
131 .Concat(self._GenerateEnumToString(cpp_namespace, type_)) 115 c.Cblock(self._GenerateTypePopulate(classname_in_namespace, type_))
132 .Append()) 116 if type_.origin.from_client:
133 c.Substitute({'classname': classname, 'namespace': cpp_namespace}) 117 c.Cblock(self._GenerateTypeToValue(classname_in_namespace, type_))
118 elif type_.property_type == PropertyType.ENUM:
119 (c.Cblock(self._GenerateEnumToString(cpp_namespace, type_))
120 .Cblock(self._GenerateEnumFromString(cpp_namespace, type_))
121 )
134 122
135 return c 123 return c
136 124
137 def _GenerateInitializersAndBody(self, type_): 125 def _GenerateInitializersAndBody(self, type_):
138 items = [] 126 items = []
139 for prop in type_.properties.values(): 127 for prop in type_.properties.values():
140 if prop.optional: 128 if prop.optional:
141 continue 129 continue
142 130
143 t = prop.type_ 131 t = prop.type_
144 if t == PropertyType.INTEGER: 132 if t.property_type == PropertyType.INTEGER:
145 items.append('%s(0)' % prop.unix_name) 133 items.append('%s(0)' % prop.unix_name)
146 elif t == PropertyType.DOUBLE: 134 elif t.property_type == PropertyType.DOUBLE:
147 items.append('%s(0.0)' % prop.unix_name) 135 items.append('%s(0.0)' % prop.unix_name)
148 elif t == PropertyType.BOOLEAN: 136 elif t.property_type == PropertyType.BOOLEAN:
149 items.append('%s(false)' % prop.unix_name) 137 items.append('%s(false)' % prop.unix_name)
150 elif t == PropertyType.BINARY: 138 elif t.property_type == PropertyType.BINARY:
151 items.append('%s(NULL)' % prop.unix_name) 139 items.append('%s(NULL)' % prop.unix_name)
152 elif (t == PropertyType.ADDITIONAL_PROPERTIES or 140 elif (t.property_type == PropertyType.ANY or
153 t == PropertyType.ANY or 141 t.property_type == PropertyType.ARRAY or
154 t == PropertyType.ARRAY or 142 t.property_type == PropertyType.CHOICES or
155 t == PropertyType.CHOICES or 143 t.property_type == PropertyType.ENUM or
156 t == PropertyType.ENUM or 144 t.property_type == PropertyType.OBJECT or
157 t == PropertyType.OBJECT or 145 t.property_type == PropertyType.FUNCTION or
158 t == PropertyType.FUNCTION or 146 t.property_type == PropertyType.REF or
159 t == PropertyType.REF or 147 t.property_type == PropertyType.STRING):
160 t == PropertyType.STRING):
161 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we 148 # TODO(miket): It would be nice to initialize CHOICES and ENUM, but we
162 # don't presently have the semantics to indicate which one of a set 149 # don't presently have the semantics to indicate which one of a set
163 # should be the default. 150 # should be the default.
164 continue 151 continue
165 else: 152 else:
166 sys.exit("Unhandled PropertyType: %s" % t) 153 raise TypeError(t)
167 154
168 if items: 155 if items:
169 s = ': %s' % (', '.join(items)) 156 s = ': %s' % (', '.join(items))
170 else: 157 else:
171 s = '' 158 s = ''
172 s = s + ' {}' 159 s = s + ' {}'
173 return Code().Append(s) 160 return Code().Append(s)
174 161
175 def _GenerateTypePopulate(self, cpp_namespace, type_): 162 def _GenerateTypePopulate(self, cpp_namespace, type_):
176 """Generates the function for populating a type given a pointer to it. 163 """Generates the function for populating a type given a pointer to it.
177 164
178 E.g for type "Foo", generates Foo::Populate() 165 E.g for type "Foo", generates Foo::Populate()
179 """ 166 """
180 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name)) 167 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
181 c = Code() 168 c = Code()
182 (c.Append('// static') 169 (c.Append('// static')
183 .Sblock('bool %(namespace)s::Populate' 170 .Append('bool %(namespace)s::Populate(')
184 '(const base::Value& value, %(name)s* out) {') 171 .Sblock(' const base::Value& value, %(name)s* out) {')
185 .Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))') 172 )
173 if type_.property_type == PropertyType.CHOICES:
174 for choice in type_.choices:
175 value_type = cpp_util.GetValueType(self._type_helper.FollowRef(choice))
176 (c.Sblock('if (value.IsType(%s)) {' % value_type)
177 .Concat(self._GeneratePopulateVariableFromValue(
178 choice,
179 '(&value)',
180 'out->as_%s' % choice.unix_name,
181 'false',
182 is_ptr=True))
183 .Append('return true;')
184 .Eblock('}')
185 )
186 c.Append('return false;')
187 elif type_.property_type == PropertyType.OBJECT:
188 (c.Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))')
186 .Append(' return false;') 189 .Append(' return false;')
187 )
188 if type_.properties:
189 (c.Append('const base::DictionaryValue* dict = '
190 'static_cast<const base::DictionaryValue*>(&value);')
191 .Append()
192 ) 190 )
191 if type_.properties or type_.additional_properties is not None:
192 c.Append('const base::DictionaryValue* dict = '
193 'static_cast<const base::DictionaryValue*>(&value);')
193 for prop in type_.properties.values(): 194 for prop in type_.properties.values():
194 c.Concat(self._InitializePropertyToDefault(prop, 'out')) 195 c.Concat(self._InitializePropertyToDefault(prop, 'out'))
195 for prop in type_.properties.values(): 196 for prop in type_.properties.values():
196 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 197 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
198 if type_.additional_properties is not None:
199 if type_.additional_properties.property_type == PropertyType.ANY:
197 c.Append('out->additional_properties.MergeDictionary(dict);') 200 c.Append('out->additional_properties.MergeDictionary(dict);')
198 # remove all keys that are actual properties
199 for cur_prop in type_.properties.values():
200 if prop != cur_prop:
201 c.Append('out->additional_properties'
202 '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name)
203 c.Append()
204 else: 201 else:
205 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out')) 202 cpp_type = self._type_helper.GetCppType(type_.additional_properties,
206 (c.Append('return true;') 203 is_in_container=True)
207 .Eblock('}') 204 (c.Append('for (base::DictionaryValue::Iterator it(*dict);')
208 ) 205 .Sblock(' it.HasNext(); it.Advance()) {')
209 c.Substitute({'namespace': cpp_namespace, 'name': classname}) 206 .Append('%s tmp;' % cpp_type)
207 .Concat(self._GeneratePopulateVariableFromValue(
208 type_.additional_properties,
209 '(&it.value())',
210 'tmp',
211 'false'))
212 .Append('out->additional_properties[it.key()] = tmp;')
213 .Eblock('}')
214 )
215 c.Append('return true;')
216 (c.Eblock('}')
217 .Substitute({'namespace': cpp_namespace, 'name': classname}))
210 return c 218 return c
211 219
212 def _GenerateTypePopulateProperty(self, prop, src, dst): 220 def _GenerateTypePopulateProperty(self, prop, src, dst):
213 """Generate the code to populate a single property in a type. 221 """Generate the code to populate a single property in a type.
214 222
215 src: base::DictionaryValue* 223 src: base::DictionaryValue*
216 dst: Type* 224 dst: Type*
217 """ 225 """
218 c = Code() 226 c = Code()
219 value_var = prop.unix_name + '_value' 227 value_var = prop.unix_name + '_value'
220 c.Append('const base::Value* %(value_var)s = NULL;') 228 c.Append('const base::Value* %(value_var)s = NULL;')
221 if prop.optional: 229 if prop.optional:
222 (c.Sblock( 230 (c.Sblock(
223 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') 231 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
224 .Concat(self._GeneratePopulatePropertyFromValue( 232 .Concat(self._GeneratePopulatePropertyFromValue(
225 prop, value_var, dst, 'false'))) 233 prop, value_var, dst, 'false')))
226 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 234 underlying_type = self._type_helper.FollowRef(prop.type_)
235 if underlying_type.property_type == PropertyType.ENUM:
227 (c.Append('} else {') 236 (c.Append('} else {')
228 .Append('%%(dst)s->%%(name)s = %s;' % 237 .Append('%%(dst)s->%%(name)s = %s;' %
229 self._cpp_type_generator.GetEnumNoneValue(prop))) 238 self._type_helper.GetEnumNoneValue(prop.type_)))
230 c.Eblock('}') 239 c.Eblock('}')
231 else: 240 else:
232 (c.Append( 241 (c.Append(
233 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') 242 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))')
234 .Append(' return false;') 243 .Append(' return false;')
235 .Concat(self._GeneratePopulatePropertyFromValue( 244 .Concat(self._GeneratePopulatePropertyFromValue(
236 prop, value_var, dst, 'false')) 245 prop, value_var, dst, 'false'))
237 ) 246 )
238 c.Append() 247 c.Append()
239 c.Substitute({ 248 c.Substitute({
240 'value_var': value_var, 249 'value_var': value_var,
241 'key': prop.name, 250 'key': prop.name,
242 'src': src, 251 'src': src,
243 'dst': dst, 252 'dst': dst,
244 'name': prop.unix_name 253 'name': prop.unix_name
245 }) 254 })
246 return c 255 return c
247 256
248 def _GenerateTypeToValue(self, cpp_namespace, type_): 257 def _GenerateTypeToValue(self, cpp_namespace, type_):
249 """Generates a function that serializes the type into a 258 """Generates a function that serializes the type into a base::Value.
250 |base::DictionaryValue|. 259 E.g. for type "Foo" generates Foo::ToValue()
260 """
261 if type_.property_type == PropertyType.OBJECT:
262 return self._GenerateObjectTypeToValue(cpp_namespace, type_)
263 elif type_.property_type == PropertyType.CHOICES:
264 return self._GenerateChoiceTypeToValue(cpp_namespace, type_)
265 else:
266 raise ValueError("Unsupported property type %s" % type_.type_)
251 267
252 E.g. for type "Foo" generates Foo::ToValue() 268 def _GenerateObjectTypeToValue(self, cpp_namespace, type_):
269 """Generates a function that serializes an object-representing type
270 into a base::DictionaryValue.
253 """ 271 """
254 c = Code() 272 c = Code()
255 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % 273 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
256 cpp_namespace) 274 cpp_namespace)
257 .Append('scoped_ptr<base::DictionaryValue> value(' 275 .Append('scoped_ptr<base::DictionaryValue> value('
258 'new base::DictionaryValue());') 276 'new base::DictionaryValue());')
259 .Append() 277 .Append()
260 ) 278 )
279
261 for prop in type_.properties.values(): 280 for prop in type_.properties.values():
262 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 281 if prop.optional:
263 c.Append('value->MergeDictionary(&%s);' % prop.unix_name) 282 # Optional enum values are generated with a NONE enum value.
283 underlying_type = self._type_helper.FollowRef(prop.type_)
284 if underlying_type.property_type == PropertyType.ENUM:
285 c.Sblock('if (%s != %s) {' %
286 (prop.unix_name,
287 self._type_helper.GetEnumNoneValue(prop.type_)))
288 else:
289 c.Sblock('if (%s.get()) {' % prop.unix_name)
290
291 # ANY is a base::Value which is abstract and cannot be a direct member, so
292 # it will always be a pointer.
293 is_ptr = prop.optional or prop.type_.property_type == PropertyType.ANY
294 c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
295 prop.name,
296 self._CreateValueFromType(prop.type_,
297 'this->%s' % prop.unix_name,
298 is_ptr=is_ptr)))
299
300 if prop.optional:
301 c.Eblock('}');
302
303 if type_.additional_properties is not None:
304 if type_.additional_properties.property_type == PropertyType.ANY:
305 c.Append('value->MergeDictionary(&additional_properties);')
264 else: 306 else:
265 if prop.optional: 307 # Non-copyable types will be wrapped in a linked_ptr for inclusion in
266 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 308 # maps, so we need to unwrap them.
267 c.Sblock('if (%s != %s) {' % 309 needs_unwrap = (
268 (prop.unix_name, 310 not self._type_helper.IsCopyable(type_.additional_properties))
269 self._cpp_type_generator.GetEnumNoneValue(prop))) 311 cpp_type = self._type_helper.GetCppType(type_.additional_properties,
270 elif prop.type_ == PropertyType.CHOICES: 312 is_in_container=True)
271 c.Sblock('if (%s_type != %s) {' % 313 (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' %
272 (prop.unix_name, 314 cpp_util.PadForGenerics(cpp_type))
273 self._cpp_type_generator.GetEnumNoneValue(prop))) 315 .Append(' additional_properties.begin();')
274 else: 316 .Append(' it != additional_properties.end(); ++it) {')
275 c.Sblock('if (%s.get()) {' % prop.unix_name) 317 .Append('value->SetWithoutPathExpansion(it->first, %s);' %
318 self._CreateValueFromType(
319 type_.additional_properties,
320 '%sit->second' % ('*' if needs_unwrap else '')))
321 .Eblock('}')
322 )
276 323
277 if prop.type_ == prop.compiled_type: 324 return (c.Append()
278 c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( 325 .Append('return value.Pass();')
279 prop.name, 326 .Eblock('}'))
280 self._CreateValueFromProperty(prop, 'this->' + prop.unix_name))) 327
281 else: 328 def _GenerateChoiceTypeToValue(self, cpp_namespace, type_):
282 conversion_src = 'this->' + prop.unix_name 329 """Generates a function that serializes a choice-representing type
283 if prop.optional: 330 into a base::Value.
284 conversion_src = '*' + conversion_src 331 """
285 (c.Append('%s %s;' % (self._cpp_type_generator.GetType(prop), 332 c = Code()
286 prop.unix_name)) 333 c.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace)
287 .Append(cpp_util.GenerateCompiledTypeToTypeConversion( 334 c.Append('scoped_ptr<base::Value> result;');
288 self._cpp_type_generator.GetReferencedProperty(prop), 335 for choice in type_.choices:
289 conversion_src, 336 choice_var = 'as_%s' % choice.unix_name
290 prop.unix_name) + ';') 337 (c.Sblock('if (%s) {' % choice_var)
291 .Append('value->SetWithoutPathExpansion("%s", %s);' % ( 338 .Append('DCHECK(!result) << "Cannot set multiple choices for %s";' %
292 prop.unix_name, 339 type_.unix_name)
293 self._CreateValueFromProperty(prop, prop.unix_name))) 340 .Append('result.reset(%s);' %
294 ) 341 self._CreateValueFromType(choice, '*%s' % choice_var))
295 if prop.optional: 342 .Eblock('}')
296 c.Eblock('}'); 343 )
297 (c.Append() 344 (c.Append('DCHECK(result) << "Must set at least one choice for %s";' %
298 .Append('return value.Pass();') 345 type_.unix_name)
346 .Append('return result.Pass();')
299 .Eblock('}') 347 .Eblock('}')
300 ) 348 )
301 return c 349 return c
302 350
303 def _GenerateFunction(self, cpp_namespace, function): 351 def _GenerateFunction(self, function):
304 """Generates the definitions for function structs. 352 """Generates the definitions for function structs.
305 """ 353 """
306 c = Code() 354 c = Code()
307 355
356 # TODO(kalman): use function.unix_name not Classname.
357 function_namespace = cpp_util.Classname(function.name)
358 (c.Append('namespace %s {' % function_namespace)
359 .Append()
360 )
361
308 # Params::Populate function 362 # Params::Populate function
309 if function.params: 363 if function.params:
310 c.Concat(self._GeneratePropertyFunctions(cpp_namespace + '::Params', 364 c.Concat(self._GeneratePropertyFunctions('Params', function.params))
311 function.params)) 365 (c.Append('Params::Params() {}')
312 (c.Append('%(cpp_namespace)s::Params::Params() {}') 366 .Append('Params::~Params() {}')
313 .Append('%(cpp_namespace)s::Params::~Params() {}')
314 .Append() 367 .Append()
315 .Concat(self._GenerateFunctionParamsCreate(cpp_namespace, function)) 368 .Cblock(self._GenerateFunctionParamsCreate(function))
316 .Append()
317 ) 369 )
318 370
319 # Results::Create function 371 # Results::Create function
320 if function.callback: 372 if function.callback:
321 c.Concat(self._GenerateCreateCallbackArguments( 373 c.Concat(self._GenerateCreateCallbackArguments('Results',
322 "%s::Results" % cpp_namespace, function.callback)) 374 function.callback))
323 375
324 c.Substitute({'cpp_namespace': cpp_namespace}) 376 c.Append('} // namespace %s' % function_namespace)
325
326 return c 377 return c
327 378
328 def _CreateValueFromProperty(self, prop, var): 379 def _GenerateEvent(self, event):
329 """Creates a base::Value given a property. Generated code passes ownership 380 # TODO(kalman): use event.unix_name not Classname.
381 c = Code()
382 event_namespace = cpp_util.Classname(event.name)
383 (c.Append('namespace %s {' % event_namespace)
384 .Append()
385 .Cblock(self._GenerateCreateCallbackArguments(None, event))
386 .Append('} // namespace %s' % event_namespace)
387 )
388 return c
389
390 def _CreateValueFromType(self, type_, var, is_ptr=False):
391 """Creates a base::Value given a type. Generated code passes ownership
330 to caller. 392 to caller.
331 393
332 var: variable or variable* 394 var: variable or variable*
333 395
334 E.g for std::string, generate base::Value::CreateStringValue(var) 396 E.g for std::string, generate base::Value::CreateStringValue(var)
335 """ 397 """
336 if prop.type_ == PropertyType.CHOICES: 398 underlying_type = self._type_helper.FollowRef(type_)
337 return 'Get%sChoiceValue().release()' % cpp_util.Classname(prop.name) 399 if (underlying_type.property_type == PropertyType.CHOICES or
338 elif self._IsObjectOrObjectRef(prop): 400 underlying_type.property_type == PropertyType.OBJECT):
339 if prop.optional: 401 if is_ptr:
340 return '%s->ToValue().release()' % var 402 return '(%s)->ToValue().release()' % var
341 else: 403 else:
342 return '%s.ToValue().release()' % var 404 return '(%s).ToValue().release()' % var
343 elif prop.type_ == PropertyType.ANY: 405 elif (underlying_type.property_type == PropertyType.ANY or
344 return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var) 406 underlying_type.property_type == PropertyType.FUNCTION):
345 elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 407 if is_ptr:
346 return '%s.DeepCopy()' % var 408 vardot = '(%s)->' % var
347 elif prop.type_ == PropertyType.FUNCTION:
348 if prop.optional:
349 vardot = var + '->'
350 else: 409 else:
351 vardot = var + '.' 410 vardot = '(%s).' % var
352 return '%sDeepCopy()' % vardot 411 return '%sDeepCopy()' % vardot
353 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 412 elif underlying_type.property_type == PropertyType.ENUM:
354 return 'base::Value::CreateStringValue(ToString(%s))' % var 413 return 'base::Value::CreateStringValue(ToString(%s))' % var
355 elif prop.type_ == PropertyType.BINARY: 414 elif underlying_type.property_type == PropertyType.BINARY:
356 if prop.optional: 415 if is_ptr:
357 vardot = var + '->' 416 vardot = var + '->'
358 else: 417 else:
359 vardot = var + '.' 418 vardot = var + '.'
360 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % 419 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' %
361 (vardot, vardot)) 420 (vardot, vardot))
362 elif self._IsArrayOrArrayRef(prop): 421 elif underlying_type.property_type == PropertyType.ARRAY:
363 return '%s.release()' % self._util_cc_helper.CreateValueFromArray( 422 return '%s.release()' % self._util_cc_helper.CreateValueFromArray(
364 self._cpp_type_generator.GetReferencedProperty(prop), var, 423 underlying_type,
365 prop.optional) 424 var,
366 elif self._IsFundamentalOrFundamentalRef(prop): 425 is_ptr)
367 # If prop.type != prop.compiled_type, then no asterisk is necessary 426 elif underlying_type.property_type.is_fundamental:
368 # because the target is a local variable and not a dereferenced scoped 427 if is_ptr:
369 # pointer. The asterisk is instead prepended to conversion_src around line 428 var = '*%s' % var
370 # 273. 429 if underlying_type.property_type == PropertyType.STRING:
371 if prop.optional and prop.type_ == prop.compiled_type: 430 return 'new base::StringValue(%s)' % var
372 var = '*' + var 431 else:
373 prop = self._cpp_type_generator.GetReferencedProperty(prop); 432 return 'new base::FundamentalValue(%s)' % var
374 return {
375 PropertyType.STRING: 'base::Value::CreateStringValue(%s)',
376 PropertyType.BOOLEAN: 'base::Value::CreateBooleanValue(%s)',
377 PropertyType.INTEGER: 'base::Value::CreateIntegerValue(%s)',
378 PropertyType.DOUBLE: 'base::Value::CreateDoubleValue(%s)',
379 }[prop.type_] % var
380 else: 433 else:
381 raise NotImplementedError('Conversion of %s to base::Value not ' 434 raise NotImplementedError('Conversion of %s to base::Value not '
382 'implemented' % repr(prop.type_)) 435 'implemented' % repr(type_.type_))
383 436
384 def _GenerateParamsCheck(self, function, var): 437 def _GenerateParamsCheck(self, function, var):
385 """Generates a check for the correct number of arguments when creating 438 """Generates a check for the correct number of arguments when creating
386 Params. 439 Params.
387 """ 440 """
388 c = Code() 441 c = Code()
389 num_required = 0 442 num_required = 0
390 for param in function.params: 443 for param in function.params:
391 if not param.optional: 444 if not param.optional:
392 num_required += 1 445 num_required += 1
393 if num_required == len(function.params): 446 if num_required == len(function.params):
394 c.Append('if (%(var)s.GetSize() != %(total)d)') 447 c.Append('if (%(var)s.GetSize() != %(total)d)')
395 elif not num_required: 448 elif not num_required:
396 c.Append('if (%(var)s.GetSize() > %(total)d)') 449 c.Append('if (%(var)s.GetSize() > %(total)d)')
397 else: 450 else:
398 c.Append('if (%(var)s.GetSize() < %(required)d' 451 c.Append('if (%(var)s.GetSize() < %(required)d'
399 ' || %(var)s.GetSize() > %(total)d)') 452 ' || %(var)s.GetSize() > %(total)d)')
400 c.Append(' return scoped_ptr<Params>();') 453 c.Append(' return scoped_ptr<Params>();')
401 c.Substitute({ 454 c.Substitute({
402 'var': var, 455 'var': var,
403 'required': num_required, 456 'required': num_required,
404 'total': len(function.params), 457 'total': len(function.params),
405 }) 458 })
406 return c 459 return c
407 460
408 def _GenerateFunctionParamsCreate(self, cpp_namespace, function): 461 def _GenerateFunctionParamsCreate(self, function):
409 """Generate function to create an instance of Params. The generated 462 """Generate function to create an instance of Params. The generated
410 function takes a base::ListValue of arguments. 463 function takes a base::ListValue of arguments.
411 464
412 E.g for function "Bar", generate Bar::Params::Create() 465 E.g for function "Bar", generate Bar::Params::Create()
413 """ 466 """
414 c = Code() 467 c = Code()
415 (c.Append('// static') 468 (c.Append('// static')
416 .Sblock('scoped_ptr<%(cpp_namespace)s::Params> ' 469 .Sblock('scoped_ptr<Params> '
417 '%(cpp_namespace)s::Params::Create(const base::ListValue& args) {') 470 'Params::Create(const base::ListValue& args) {')
418 .Concat(self._GenerateParamsCheck(function, 'args')) 471 .Concat(self._GenerateParamsCheck(function, 'args'))
419 .Append('scoped_ptr<Params> params(new Params());') 472 .Append('scoped_ptr<Params> params(new Params());')
420 ) 473 )
421 c.Substitute({'cpp_namespace': cpp_namespace})
422 474
423 for param in function.params: 475 for param in function.params:
424 c.Concat(self._InitializePropertyToDefault(param, 'params')) 476 c.Concat(self._InitializePropertyToDefault(param, 'params'))
425 477
426 for i, param in enumerate(function.params): 478 for i, param in enumerate(function.params):
427 # Any failure will cause this function to return. If any argument is 479 # Any failure will cause this function to return. If any argument is
428 # incorrect or missing, those following it are not processed. Note that 480 # incorrect or missing, those following it are not processed. Note that
429 # for optional arguments, we allow missing arguments and proceed because 481 # for optional arguments, we allow missing arguments and proceed because
430 # there may be other arguments following it. 482 # there may be other arguments following it.
431 failure_value = 'scoped_ptr<Params>()' 483 failure_value = 'scoped_ptr<Params>()'
432 c.Append() 484 c.Append()
433 value_var = param.unix_name + '_value' 485 value_var = param.unix_name + '_value'
434 (c.Append('const base::Value* %(value_var)s = NULL;') 486 (c.Append('const base::Value* %(value_var)s = NULL;')
435 .Append('if (args.Get(%(i)s, &%(value_var)s) &&\n' 487 .Append('if (args.Get(%(i)s, &%(value_var)s) &&')
436 ' !%(value_var)s->IsType(base::Value::TYPE_NULL))') 488 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {')
437 .Sblock('{')
438 .Concat(self._GeneratePopulatePropertyFromValue( 489 .Concat(self._GeneratePopulatePropertyFromValue(
439 param, value_var, 'params', failure_value)) 490 param, value_var, 'params', failure_value))
440 .Eblock('}') 491 .Eblock('}')
441 ) 492 )
442 if not param.optional: 493 if not param.optional:
443 (c.Sblock('else {') 494 (c.Sblock('else {')
444 .Append('return %s;' % failure_value) 495 .Append('return %s;' % failure_value)
445 .Eblock('}') 496 .Eblock('}')
446 ) 497 )
447 c.Substitute({'value_var': value_var, 'i': i}) 498 c.Substitute({'value_var': value_var, 'i': i})
448 (c.Append() 499 (c.Append()
449 .Append('return params.Pass();') 500 .Append('return params.Pass();')
450 .Eblock('}') 501 .Eblock('}')
451 .Append() 502 .Append()
452 ) 503 )
453 504
454 return c 505 return c
455 506
456 def _GeneratePopulatePropertyFromValue( 507 def _GeneratePopulatePropertyFromValue(self,
457 self, prop, value_var, dst, failure_value, check_type=True): 508 prop,
458 """Generates code to populate a model.Property given a base::Value*. The 509 src_var,
459 existence of data inside the base::Value* is assumed so checks for existence 510 dst_class_var,
460 should be performed before the code this generates. 511 failure_value):
461 512 """Generates code to populate property |prop| of |dst_class_var| (a
462 prop: the property the code is populating. 513 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for
463 value_var: a base::Value* that should represent |prop|. 514 semantics.
464 dst: the object with |prop| as a member. 515 """
465 failure_value: the value to return if |prop| cannot be extracted from 516 return self._GeneratePopulateVariableFromValue(prop.type_,
466 |value_var| 517 src_var,
467 check_type: if true, will check if |value_var| is the correct 518 '%s->%s' % (dst_class_var,
468 base::Value::Type 519 prop.unix_name),
520 failure_value,
521 is_ptr=prop.optional)
522
523 def _GeneratePopulateVariableFromValue(self,
524 type_,
525 src_var,
526 dst_var,
527 failure_value,
528 is_ptr=False):
529 """Generates code to populate a variable |dst_var| of type |type_| from a
530 Value* at |src_var|. The Value* is assumed to be non-NULL. In the generated
531 code, if |dst_var| fails to be populated then Populate will return
532 |failure_value|.
469 """ 533 """
470 c = Code() 534 c = Code()
471 c.Sblock('{') 535 c.Sblock('{')
472 536
473 if self._IsFundamentalOrFundamentalRef(prop): 537 underlying_type = self._type_helper.FollowRef(type_)
474 self._GenerateFundamentalOrFundamentalRefPopulate(c, prop, value_var, dst) 538
475 elif self._IsObjectOrObjectRef(prop): 539 if underlying_type.property_type.is_fundamental:
476 self._GenerateObjectOrObjectRefPopulate(c, prop) 540 if is_ptr:
477 elif prop.type_ == PropertyType.FUNCTION: 541 (c.Append('%(cpp_type)s temp;')
478 self._GenerateFunctionPopulate(c, prop) 542 .Append('if (!%s)' % cpp_util.GetAsFundamentalValue(
479 elif prop.type_ == PropertyType.ANY: 543 self._type_helper.FollowRef(type_), src_var, '&temp'))
480 self._GenerateAnyPopulate(c, prop, value_var, dst) 544 .Append(' return %(failure_value)s;')
481 elif self._IsArrayOrArrayRef(prop): 545 .Append('%(dst_var)s.reset(new %(cpp_type)s(temp));')
482 self._GenerateArrayOrArrayRefPopulate(c, prop, dst) 546 )
483 elif prop.type_ == PropertyType.CHOICES: 547 else:
484 self._GenerateChoicePopulate(c, prop, value_var, dst, failure_value) 548 (c.Append('if (!%s)' % cpp_util.GetAsFundamentalValue(
485 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 549 self._type_helper.FollowRef(type_),
486 self._GenerateEnumPopulate(c, prop, value_var) 550 src_var,
487 elif prop.type_ == PropertyType.BINARY: 551 '&%s' % dst_var))
488 self._GenerateBinaryPopulate(c, prop) 552 .Append(' return %(failure_value)s;')
553 )
554 elif underlying_type.property_type == PropertyType.OBJECT:
555 if is_ptr:
556 (c.Append('const base::DictionaryValue* dictionary = NULL;')
557 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))')
558 .Append(' return %(failure_value)s;')
559 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
560 .Append('if (!%(cpp_type)s::Populate(*dictionary, temp.get()))')
561 .Append(' return %(failure_value)s;')
562 .Append('%(dst_var)s = temp.Pass();')
563 )
564 else:
565 (c.Append('const base::DictionaryValue* dictionary = NULL;')
566 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))')
567 .Append(' return %(failure_value)s;')
568 .Append('if (!%(cpp_type)s::Populate(*dictionary, &%(dst_var)s))')
569 .Append(' return %(failure_value)s;')
570 )
571 elif underlying_type.property_type == PropertyType.FUNCTION:
572 if is_ptr:
573 c.Append('%(dst_var)s.reset(new base::DictionaryValue());')
574 elif underlying_type.property_type == PropertyType.ANY:
575 c.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());')
576 elif underlying_type.property_type == PropertyType.ARRAY:
577 # util_cc_helper deals with optional and required arrays
578 (c.Append('const base::ListValue* list = NULL;')
579 .Append('if (!%(src_var)s->GetAsList(&list))')
580 .Append(' return %(failure_value)s;'))
581 item_type = underlying_type.item_type
582 if item_type.property_type == PropertyType.ENUM:
583 c.Concat(self._GenerateListValueToEnumArrayConversion(
584 item_type,
585 'list',
586 dst_var,
587 failure_value,
588 is_ptr=is_ptr))
589 else:
590 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList(
591 underlying_type,
592 'list',
593 dst_var,
594 is_ptr))
595 .Append(' return %(failure_value)s;')
596 )
597 elif underlying_type.property_type == PropertyType.CHOICES:
598 if is_ptr:
599 (c.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
600 .Append('if (!%(cpp_type)s::Populate(*%(src_var)s, temp.get()))')
601 .Append(' return %(failure_value)s;')
602 .Append('%(dst_var)s = temp.Pass();')
603 )
604 else:
605 (c.Append('if (!%(cpp_type)s::Populate(*%(src_var)s, &%(dst_var)s))')
606 .Append(' return %(failure_value)s;')
607 )
608 elif underlying_type.property_type == PropertyType.ENUM:
609 c.Concat(self._GenerateStringToEnumConversion(type_,
610 src_var,
611 dst_var,
612 failure_value))
613 elif underlying_type.property_type == PropertyType.BINARY:
614 (c.Append('if (!%(src_var)s->IsType(%(value_type)s))')
615 .Append(' return %(failure_value)s;')
616 .Append('const base::BinaryValue* binary_value =')
617 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);')
618 )
619 if is_ptr:
620 (c.Append('%(dst_var)s.reset(')
621 .Append(' new std::string(binary_value->GetBuffer(),')
622 .Append(' binary_value->GetSize()));')
623 )
624 else:
625 (c.Append('%(dst_var)s.assign(binary_value->GetBuffer(),')
626 .Append(' binary_value->GetSize());')
627 )
489 else: 628 else:
490 raise NotImplementedError(prop.type_) 629 raise NotImplementedError(type_)
491 c.Eblock('}') 630
492 sub = { 631 sub = {
493 'value_var': value_var, 632 'cpp_type': self._type_helper.GetCppType(type_),
494 'name': prop.unix_name, 633 'src_var': src_var,
495 'dst': dst, 634 'dst_var': dst_var,
496 'failure_value': failure_value, 635 'failure_value': failure_value,
497 } 636 }
498 if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): 637
499 sub['ctype'] = self._cpp_type_generator.GetType(prop) 638 if underlying_type.property_type not in (PropertyType.ANY,
500 sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType(prop) 639 PropertyType.CHOICES):
501 sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator 640 sub['value_type'] = cpp_util.GetValueType(underlying_type)
502 .GetReferencedProperty(prop).type_) 641
503 c.Substitute(sub) 642 return c.Eblock('}').Substitute(sub)
504 return c 643
505 644 def _GenerateListValueToEnumArrayConversion(self,
506 def _GenerateFundamentalOrFundamentalRefPopulate(self, 645 item_type,
507 c, 646 src_var,
508 prop, 647 dst_var,
509 value_var, 648 failure_value,
510 dst): 649 is_ptr=False):
511 if prop.optional: 650 """Returns Code that converts a ListValue of string constants from
512 (c.Append('%(ctype)s temp;') 651 |src_var| into an array of enums of |type_| in |dst_var|. On failure,
513 .Append('if (!%s)' % 652 returns |failure_value|.
514 cpp_util.GetAsFundamentalValue( 653 """
515 self._cpp_type_generator.GetReferencedProperty(prop), 654 c = Code()
516 value_var, 655 accessor = '.'
517 '&temp')) 656 if is_ptr:
518 .Append(' return %(failure_value)s;') 657 accessor = '->'
519 ) 658 cpp_type = self._type_helper.GetCppType(item_type, is_in_container=True)
520 if prop.type_ != prop.compiled_type: 659 c.Append('%s.reset(new std::vector<%s>);' %
521 (c.Append('%(compiled_ctype)s temp2;') 660 (dst_var, cpp_util.PadForGenerics(cpp_type)))
522 .Append('if (!%s)' % 661 (c.Sblock('for (base::ListValue::const_iterator it = %s->begin(); '
523 cpp_util.GenerateTypeToCompiledTypeConversion( 662 'it != %s->end(); ++it) {' % (src_var, src_var))
524 self._cpp_type_generator.GetReferencedProperty(prop), 663 .Append('%s tmp;' % self._type_helper.GetCppType(item_type))
525 'temp', 664 .Concat(self._GenerateStringToEnumConversion(item_type,
526 'temp2')) 665 '(*it)',
527 .Append(' return %(failure_value)s;') 666 'tmp',
528 .Append('%(dst)s->%(name)s.reset(new %(compiled_ctype)s(temp2));') 667 failure_value))
529 ) 668 .Append('%s%spush_back(tmp);' % (dst_var, accessor))
530 else:
531 c.Append('%(dst)s->%(name)s.reset(new %(ctype)s(temp));')
532
533 else:
534 if prop.type_ == prop.compiled_type:
535 assignment_target = '&%s->%s' % (dst, prop.unix_name)
536 else:
537 c.Append('%(ctype)s temp;')
538 assignment_target = '&temp'
539 (c.Append('if (!%s)' %
540 cpp_util.GetAsFundamentalValue(
541 self._cpp_type_generator.GetReferencedProperty(prop),
542 value_var,
543 assignment_target))
544 .Append(' return %(failure_value)s;')
545 )
546 if prop.type_ != prop.compiled_type:
547 (c.Append('if (!%s)' %
548 cpp_util.GenerateTypeToCompiledTypeConversion(
549 self._cpp_type_generator.GetReferencedProperty(prop),
550 'temp',
551 '%s->%s' % (dst, prop.unix_name)))
552 .Append(' return %(failure_value)s;')
553 )
554
555 def _GenerateObjectOrObjectRefPopulate(self, c, prop):
556 if prop.optional:
557 (c.Append('const base::DictionaryValue* dictionary = NULL;')
558 .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))')
559 .Append(' return %(failure_value)s;')
560 .Append('scoped_ptr<%(ctype)s> temp(new %(ctype)s());')
561 .Append('if (!%(ctype)s::Populate(*dictionary, temp.get()))')
562 .Append(' return %(failure_value)s;')
563 .Append('%(dst)s->%(name)s = temp.Pass();')
564 )
565 else:
566 (c.Append('const base::DictionaryValue* dictionary = NULL;')
567 .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))')
568 .Append(' return %(failure_value)s;')
569 .Append(
570 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))')
571 .Append(' return %(failure_value)s;')
572 )
573
574 def _GenerateFunctionPopulate(self, c, prop):
575 if prop.optional:
576 c.Append('%(dst)s->%(name)s.reset(new base::DictionaryValue());')
577
578 def _GenerateAnyPopulate(self, c, prop, value_var, dst):
579 if prop.optional:
580 c.Append('%(dst)s->%(name)s.reset(new ' + any_helper.ANY_CLASS + '());')
581 c.Append(self._any_helper.Init(prop, value_var, dst) + ';')
582
583 def _GenerateArrayOrArrayRefPopulate(self, c, prop, dst):
584 # util_cc_helper deals with optional and required arrays
585 (c.Append('const base::ListValue* list = NULL;')
586 .Append('if (!%(value_var)s->GetAsList(&list))')
587 .Append(' return %(failure_value)s;'))
588 if prop.item_type.type_ == PropertyType.ENUM:
589 self._GenerateListValueToEnumArrayConversion(c, prop)
590 else:
591 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList(
592 self._cpp_type_generator.GetReferencedProperty(prop), 'list',
593 dst + '->' + prop.unix_name, prop.optional))
594 .Append(' return %(failure_value)s;')
595 )
596
597 def _GenerateChoicePopulate(self, c, prop, value_var, dst, failure_value):
598 type_var = '%(dst)s->%(name)s_type'
599 c.Sblock('switch (%(value_var)s->GetType()) {')
600 for choice in self._cpp_type_generator.ExpandParams([prop]):
601 (c.Sblock('case %s: {' % cpp_util.GetValueType(
602 self._cpp_type_generator.GetReferencedProperty(choice).type_))
603 .Concat(self._GeneratePopulatePropertyFromValue(
604 choice, value_var, dst, failure_value, check_type=False))
605 .Append('%s = %s;' %
606 (type_var,
607 self._cpp_type_generator.GetEnumValue(
608 prop, choice.type_.name)))
609 .Append('break;')
610 .Eblock('}') 669 .Eblock('}')
611 ) 670 )
612 (c.Append('default:') 671 return c
613 .Append(' return %(failure_value)s;') 672
614 ) 673 def _GenerateStringToEnumConversion(self,
615 c.Eblock('}') 674 type_,
616 675 src_var,
617 def _GenerateEnumPopulate(self, c, prop, value_var): 676 dst_var,
618 c.Sblock('{') 677 failure_value):
619 self._GenerateStringToEnumConversion(c, prop, value_var, 'enum_temp') 678 """Returns Code that converts a string type in |src_var| to an enum with
620 c.Append('%(dst)s->%(name)s = enum_temp;') 679 type |type_| in |dst_var|. In the generated code, if |src_var| is not
621 c.Eblock('}') 680 a valid enum name then the function will return |failure_value|.
622 681 """
623 def _GenerateBinaryPopulate(self, c, prop): 682 c = Code()
624 (c.Append('if (!%(value_var)s->IsType(%(value_type)s))') 683 enum_as_string = '%s_as_string' % type_.unix_name
625 .Append(' return %(failure_value)s;') 684 (c.Append('std::string %s;' % enum_as_string)
626 .Append('const base::BinaryValue* binary_value =') 685 .Append('if (!%s->GetAsString(&%s))' % (src_var, enum_as_string))
627 .Append(' static_cast<const base::BinaryValue*>(%(value_var)s);') 686 .Append(' return %s;' % failure_value)
628 ) 687 .Append('%s = Parse%s(%s);' % (dst_var,
629 if prop.optional: 688 self._type_helper.GetCppType(type_),
630 (c.Append('%(dst)s->%(name)s.reset(') 689 enum_as_string))
631 .Append(' new std::string(binary_value->GetBuffer(),') 690 .Append('if (%s == %s)' % (dst_var,
632 .Append(' binary_value->GetSize()));') 691 self._type_helper.GetEnumNoneValue(type_)))
633 ) 692 .Append(' return %s;' % failure_value)
634 else: 693 )
635 (c.Append('%(dst)s->%(name)s.assign(binary_value->GetBuffer(),') 694 return c
636 .Append(' binary_value->GetSize());') 695
637 ) 696 def _GeneratePropertyFunctions(self, namespace, params):
638 697 """Generates the member functions for a list of parameters.
639 def _GenerateListValueToEnumArrayConversion(self, c, prop): 698 """
640 """Appends code that converts a ListValue of string contstants to 699 return self._GenerateTypes(namespace, (param.type_ for param in params))
641 an array of enums in dst. 700
642 Leaves dst, name, and failure_value unsubstituted. 701 def _GenerateTypes(self, namespace, types):
643 702 """Generates the member functions for a list of types.
644 c: the Code object that is being appended to. 703 """
645 prop: the property that the code is populating. 704 c = Code()
646 """ 705 for type_ in types:
647 accessor = '.' 706 c.Cblock(self._GenerateType(namespace, type_))
648 if prop.optional: 707 return c
649 c.Append('%(dst)s->%(name)s.reset(new std::vector<' + ( 708
650 self._cpp_type_generator.GetType(prop.item_type) + '>);')) 709 def _GenerateEnumToString(self, cpp_namespace, type_):
651 accessor = '->'
652 c.Sblock('for (ListValue::const_iterator it = list->begin(); '
653 'it != list->end(); ++it) {')
654 self._GenerateStringToEnumConversion(
655 c, prop.item_type, '(*it)', 'enum_temp')
656 c.Append('%(dst)s->%(name)s' + accessor + 'push_back(enum_temp);')
657 c.Eblock('}')
658
659 def _GenerateStringToEnumConversion(self, c, prop, value_var, enum_temp):
660 """Appends code that converts a string to an enum.
661 Leaves failure_value unsubstituted.
662
663 c: the code that is appended to.
664 prop: the property that the code is populating.
665 value_var: the string value that is being converted.
666 enum_temp: the name used to store the temporary enum value.
667 """
668 (c.Append('std::string enum_as_string;')
669 .Append('if (!%s->GetAsString(&enum_as_string))' % value_var)
670 .Append(' return %(failure_value)s;')
671 .Append('%(type)s %(enum)s = From%(type)sString(enum_as_string);' % {
672 'type': self._cpp_type_generator.GetCompiledType(prop),
673 'enum': enum_temp
674 })
675 .Append('if (%s == %s)' %
676 (enum_temp, self._cpp_type_generator.GetEnumNoneValue(prop)))
677 .Append(' return %(failure_value)s;'))
678
679 def _GeneratePropertyFunctions(self, param_namespace, params):
680 """Generate the functions for structures generated by a property such as
681 CreateEnumValue for ENUMs and Populate/ToValue for Params/Results objects.
682 """
683 c = Code()
684 for param in params:
685 if param.type_ == PropertyType.OBJECT:
686 c.Concat(self._GenerateType(
687 param_namespace + '::' + cpp_util.Classname(param.name),
688 param))
689 c.Append()
690 elif param.type_ == PropertyType.ARRAY:
691 c.Concat(self._GeneratePropertyFunctions(
692 param_namespace, [param.item_type]))
693 elif param.type_ == PropertyType.CHOICES:
694 c.Concat(self._GeneratePropertyFunctions(
695 param_namespace, param.choices.values()))
696 if param.from_client:
697 c.Concat(self._GenerateGetChoiceValue(param_namespace, param))
698 elif param.type_ == PropertyType.ENUM:
699 (c.Concat(self._GenerateCreateEnumValue(param_namespace, param))
700 .Append()
701 .Concat(self._GenerateEnumFromString(param_namespace,
702 param,
703 use_namespace=True))
704 .Append()
705 .Concat(self._GenerateEnumToString(param_namespace,
706 param,
707 use_namespace=True))
708 .Append())
709 return c
710
711 def _GenerateGetChoiceValue(self, cpp_namespace, prop):
712 """Generates Get<Type>ChoiceValue() that returns a scoped_ptr<base::Value>
713 representing the choice value.
714 """
715 c = Code()
716 (c.Sblock('scoped_ptr<base::Value> '
717 '%(cpp_namespace)s::Get%(choice)sChoiceValue() const {')
718 .Sblock('switch (%s_type) {' % prop.unix_name)
719 .Concat(self._GenerateReturnCase(
720 self._cpp_type_generator.GetEnumNoneValue(prop),
721 'scoped_ptr<base::Value>()')))
722 for choice in self._cpp_type_generator.ExpandParams([prop]):
723 c.Concat(self._GenerateReturnCase(
724 self._cpp_type_generator.GetEnumValue(prop, choice.type_.name),
725 'make_scoped_ptr<base::Value>(%s)' %
726 self._CreateValueFromProperty(choice, choice.unix_name)))
727 (c.Eblock('}')
728 .Append('return scoped_ptr<base::Value>();')
729 .Eblock('}')
730 .Append()
731 .Substitute({
732 'cpp_namespace': cpp_namespace,
733 'choice': cpp_util.Classname(prop.name)
734 })
735 )
736 return c
737
738 def _GenerateCreateEnumTypeValue(self, cpp_namespace, prop):
739 """Generates CreateEnumValue() that returns the base::StringValue
740 representation of an enum type.
741 """
742 c = Code()
743 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name))
744 (c.Sblock('scoped_ptr<base::Value> CreateEnumValue(%s %s) {' %
745 (classname, classname.lower()))
746 .Append('std::string enum_temp = ToString(%s);' % classname.lower())
747 .Append('if (enum_temp.empty())')
748 .Append(' return scoped_ptr<base::Value>();')
749 .Append('return scoped_ptr<base::Value>('
750 'base::Value::CreateStringValue(enum_temp));')
751 .Eblock('}'))
752 return c
753
754 def _GenerateEnumToString(self, cpp_namespace, prop, use_namespace=False):
755 """Generates ToString() which gets the string representation of an enum. 710 """Generates ToString() which gets the string representation of an enum.
756 """ 711 """
757 c = Code() 712 c = Code()
758 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 713 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
759 if use_namespace: 714
760 namespace = '%s::' % cpp_namespace 715 if cpp_namespace is not None:
761 else: 716 c.Append('// static')
762 namespace = '' 717 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace
763 718
764 (c.Append('// static') 719 c.Sblock('std::string %sToString(%s enum_param) {' %
765 .Sblock('std::string %(namespace)sToString(%(class)s enum_param) {')) 720 (maybe_namespace, classname))
766 enum_prop = self._cpp_type_generator.GetReferencedProperty(prop)
767 c.Sblock('switch (enum_param) {') 721 c.Sblock('switch (enum_param) {')
768 for enum_value in enum_prop.enum_values: 722 for enum_value in self._type_helper.FollowRef(type_).enum_values:
769 c.Concat(self._GenerateReturnCase( 723 (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value))
770 self._cpp_type_generator.GetEnumValue(prop, enum_value), 724 .Append(' return "%s";' % enum_value))
771 '"%s"' % enum_value)) 725 (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_))
772 (c.Append('case %s:' % self._cpp_type_generator.GetEnumNoneValue(prop))
773 .Append(' return "";') 726 .Append(' return "";')
774 .Eblock('}') 727 .Eblock('}')
728 .Append('NOTREACHED();')
775 .Append('return "";') 729 .Append('return "";')
776 .Eblock('}') 730 .Eblock('}')
777 .Substitute({ 731 )
778 'namespace': namespace, 732 return c
779 'class': classname 733
780 })) 734 def _GenerateEnumFromString(self, cpp_namespace, type_):
781 return c
782
783 def _GenerateEnumFromString(self, cpp_namespace, prop, use_namespace=False):
784 """Generates FromClassNameString() which gets an enum from its string 735 """Generates FromClassNameString() which gets an enum from its string
785 representation. 736 representation.
786 """ 737 """
787 c = Code() 738 c = Code()
788 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 739 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
789 if use_namespace: 740
790 namespace = '%s::' % cpp_namespace 741 if cpp_namespace is not None:
791 else: 742 c.Append('// static')
792 namespace = '' 743 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace
793 744
794 (c.Append('// static') 745 c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
795 .Sblock('%(namespace)s%(class)s' 746 (maybe_namespace, classname, maybe_namespace, classname))
796 ' %(namespace)sFrom%(class)sString('
797 'const std::string& enum_string) {'))
798 enum_prop = self._cpp_type_generator.GetReferencedProperty(prop)
799 for i, enum_value in enumerate( 747 for i, enum_value in enumerate(
800 self._cpp_type_generator.GetReferencedProperty(prop).enum_values): 748 self._type_helper.FollowRef(type_).enum_values):
801 # This is broken up into all ifs with no else ifs because we get 749 # This is broken up into all ifs with no else ifs because we get
802 # "fatal error C1061: compiler limit : blocks nested too deeply" 750 # "fatal error C1061: compiler limit : blocks nested too deeply"
803 # on Windows. 751 # on Windows.
804 (c.Append('if (enum_string == "%s")' % enum_value) 752 (c.Append('if (enum_string == "%s")' % enum_value)
805 .Append(' return %s;' % 753 .Append(' return %s;' %
806 self._cpp_type_generator.GetEnumValue(prop, enum_value))) 754 self._type_helper.GetEnumValue(type_, enum_value)))
807 (c.Append('return %s;' % 755 (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_))
808 self._cpp_type_generator.GetEnumNoneValue(prop))
809 .Eblock('}') 756 .Eblock('}')
810 .Substitute({ 757 )
811 'namespace': namespace, 758 return c
812 'class': classname 759
813 })) 760 def _GenerateCreateCallbackArguments(self, function_scope, callback):
814 return c
815
816 # TODO(chebert): This is basically the same as GenerateCreateEnumTypeValue().
817 # The plan is to phase out the old-style enums, and make all enums into REF
818 # types.
819 def _GenerateCreateEnumValue(self, cpp_namespace, prop):
820 """Generates CreateEnumValue() that returns the base::StringValue
821 representation of an enum.
822 """
823 c = Code()
824 (c.Append('// static')
825 .Sblock('scoped_ptr<base::Value> %(cpp_namespace)s::CreateEnumValue('
826 '%(arg)s) {')
827 .Append('std::string enum_temp = ToString(%s);' % prop.unix_name)
828 .Append('if (enum_temp.empty())')
829 .Append(' return scoped_ptr<base::Value>();')
830 .Append('return scoped_ptr<base::Value>('
831 'base::Value::CreateStringValue(enum_temp));')
832 .Eblock('}')
833 .Substitute({
834 'cpp_namespace': cpp_namespace,
835 'arg': cpp_util.GetParameterDeclaration(
836 prop, self._cpp_type_generator.GetType(prop))
837 }))
838 return c
839
840 def _GenerateReturnCase(self, case_value, return_value):
841 """Generates a single return case for a switch block.
842 """
843 c = Code()
844 (c.Append('case %s:' % case_value)
845 .Append(' return %s;' % return_value)
846 )
847 return c
848
849 def _GenerateCreateCallbackArguments(self,
850 function_scope,
851 callback,
852 generate_to_json=False):
853 """Generate all functions to create Value parameters for a callback. 761 """Generate all functions to create Value parameters for a callback.
854 762
855 E.g for function "Bar", generate Bar::Results::Create 763 E.g for function "Bar", generate Bar::Results::Create
856 E.g for event "Baz", generate Baz::Create 764 E.g for event "Baz", generate Baz::Create
857 765
858 function_scope: the function scope path, e.g. Foo::Bar for the function 766 function_scope: the function scope path, e.g. Foo::Bar for the function
859 Foo::Bar::Baz(). 767 Foo::Bar::Baz(). May be None if there is no function scope.
860 callback: the Function object we are creating callback arguments for. 768 callback: the Function object we are creating callback arguments for.
861 generate_to_json: Generate a ToJson method.
862 """ 769 """
863 c = Code() 770 c = Code()
864 params = callback.params 771 params = callback.params
865 expanded_params = self._cpp_type_generator.ExpandParams(params) 772 c.Concat(self._GeneratePropertyFunctions(function_scope, params))
866 c.Concat(self._GeneratePropertyFunctions(function_scope, expanded_params)) 773
867 774 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s'
868 param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) 775 'Create(%(declaration_list)s) {')
869 for param_list in param_lists: 776 .Append('scoped_ptr<base::ListValue> create_results('
870 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::' 777 'new base::ListValue());')
871 'Create(%(declaration_list)s) {') 778 )
872 .Append('scoped_ptr<base::ListValue> create_results(' 779 declaration_list = []
873 'new base::ListValue());') 780 for param in params:
874 ) 781 declaration_list.append(cpp_util.GetParameterDeclaration(
875 declaration_list = [] 782 param, self._type_helper.GetCppType(param.type_)))
876 for param in param_list: 783 c.Append('create_results->Append(%s);' %
877 # We treat this argument as 'required' to avoid wrapping it in a 784 self._CreateValueFromType(param.type_, param.unix_name))
878 # scoped_ptr if it's optional. 785 c.Append('return create_results.Pass();')
879 param_copy = param.Copy() 786 c.Eblock('}')
880 param_copy.optional = False 787 c.Substitute({
881 declaration_list.append("const %s" % cpp_util.GetParameterDeclaration( 788 'function_scope': ('%s::' % function_scope) if function_scope else '',
882 param_copy, self._cpp_type_generator.GetCompiledType(param_copy))) 789 'declaration_list': ', '.join(declaration_list),
883 param_name = param_copy.unix_name 790 'param_names': ', '.join(param.unix_name for param in params)
884 if param_copy.type_ != param_copy.compiled_type: 791 })
885 param_name = 'temp_' + param_name
886 (c.Append('%s %s;' % (self._cpp_type_generator.GetType(param_copy),
887 param_name))
888 .Append(cpp_util.GenerateCompiledTypeToTypeConversion(
889 param_copy,
890 param_copy.unix_name,
891 param_name) + ';')
892 )
893 c.Append('create_results->Append(%s);' %
894 self._CreateValueFromProperty(param_copy, param_name))
895
896 c.Append('return create_results.Pass();')
897 c.Eblock('}')
898 if generate_to_json:
899 c.Append()
900 (c.Sblock('std::string %(function_scope)s::'
901 'ToJson(%(declaration_list)s) {')
902 .Append('scoped_ptr<base::ListValue> create_results = '
903 '%(function_scope)s::Create(%(param_list)s);')
904 .Append('std::string json;')
905 .Append('base::JSONWriter::Write(create_results.get(), &json);')
906 .Append('return json;')
907 )
908 c.Eblock('}')
909
910 c.Substitute({
911 'function_scope': function_scope,
912 'declaration_list': ', '.join(declaration_list),
913 'param_list': ', '.join(param.unix_name for param in param_list)
914 })
915
916 return c 792 return c
917 793
918 def _InitializePropertyToDefault(self, prop, dst): 794 def _InitializePropertyToDefault(self, prop, dst):
919 """Initialize a model.Property to its default value inside an object. 795 """Initialize a model.Property to its default value inside an object.
920 796
921 E.g for optional enum "state", generate dst->state = STATE_NONE; 797 E.g for optional enum "state", generate dst->state = STATE_NONE;
922 798
923 dst: Type* 799 dst: Type*
924 """ 800 """
925 c = Code() 801 c = Code()
926 if (self._cpp_type_generator.IsEnumOrEnumRef(prop) or 802 underlying_type = self._type_helper.FollowRef(prop.type_)
927 prop.type_ == PropertyType.CHOICES): 803 if (underlying_type.property_type == PropertyType.ENUM and
928 if prop.optional: 804 prop.optional):
929 prop_name = prop.unix_name 805 c.Append('%s->%s = %s;' % (
930 if prop.type_ == PropertyType.CHOICES: 806 dst,
931 prop_name = prop.unix_name + '_type' 807 prop.unix_name,
932 c.Append('%s->%s = %s;' % ( 808 self._type_helper.GetEnumNoneValue(prop.type_)))
933 dst,
934 prop_name,
935 self._cpp_type_generator.GetEnumNoneValue(prop)))
936 return c 809 return c
937
938 def _IsObjectOrObjectRef(self, prop):
939 """Determines if this property is an Object or is a ref to an Object.
940 """
941 return (self._cpp_type_generator.GetReferencedProperty(prop).type_ ==
942 PropertyType.OBJECT)
943
944 def _IsArrayOrArrayRef(self, prop):
945 """Determines if this property is an Array or is a ref to an Array.
946 """
947 return (self._cpp_type_generator.GetReferencedProperty(prop).type_ ==
948 PropertyType.ARRAY)
949
950 def _IsFundamentalOrFundamentalRef(self, prop):
951 """Determines if this property is a Fundamental type or is a ref to a
952 Fundamental type.
953 """
954 return (self._cpp_type_generator.GetReferencedProperty(prop).type_.
955 is_fundamental)
OLDNEW
« no previous file with comments | « tools/json_schema_compiler/api_gen_util.gyp ('k') | tools/json_schema_compiler/code.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698