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

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: 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
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(type(t))
Yoyo Zhou 2013/01/15 01:49:25 type(t)?
not at google - send to devlin 2013/01/15 21:47:27 I presume you mean this should be just "t" not "ty
Yoyo Zhou 2013/01/16 23:14:39 Well I didn't understand what the type(t) was for.
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 .Sblock('bool %(namespace)s::Populate('
184 '(const base::Value& value, %(name)s* out) {') 171 'const base::Value& value, %(name)s* out) {')
Yoyo Zhou 2013/01/15 01:49:25 nit: this indent looks worse than before
not at google - send to devlin 2013/01/15 21:47:27 It's so that it matches up with how you'd usually
Yoyo Zhou 2013/01/16 23:14:39 I think it gives you the false sense that the line
not at google - send to devlin 2013/01/17 00:11:49 Done.
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 # Choices fields are scoped_ptrs, so pretend they're optional.
183 is_optional=True))
Yoyo Zhou 2013/01/15 01:49:25 Is it worth it to rename this (because optionality
not at google - send to devlin 2013/01/15 21:47:27 Done. I did it throughout the compiler, since what
184 .Append('return true;')
185 .Eblock('}')
186 )
187 c.Append('return false;')
188 elif type_.property_type == PropertyType.OBJECT:
189 (c.Append('if (!value.IsType(base::Value::TYPE_DICTIONARY))')
186 .Append(' return false;') 190 .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 ) 191 )
192 if type_.properties or type_.additional_properties is not None:
193 c.Append('const base::DictionaryValue* dict = '
194 'static_cast<const base::DictionaryValue*>(&value);')
193 for prop in type_.properties.values(): 195 for prop in type_.properties.values():
194 c.Concat(self._InitializePropertyToDefault(prop, 'out')) 196 c.Concat(self._InitializePropertyToDefault(prop, 'out'))
195 for prop in type_.properties.values(): 197 for prop in type_.properties.values():
196 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 198 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
197 c.Append('out->additional_properties.MergeDictionary(dict);') 199 if type_.additional_properties is not None:
198 # remove all keys that are actual properties 200 cpp_type = self._type_helper.GetCppType(type_.additional_properties,
199 for cur_prop in type_.properties.values(): 201 is_in_container=True)
200 if prop != cur_prop: 202 (c.Append('for (base::DictionaryValue::Iterator it(*dict);')
201 c.Append('out->additional_properties' 203 .Sblock(' it.HasNext(); it.Advance()) {')
202 '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name) 204 .Append('%s tmp;' % cpp_type.strip())
Yoyo Zhou 2013/01/15 01:49:25 why do you need both is_in_container=True and stri
not at google - send to devlin 2013/01/15 21:47:27 Added comment.
Yoyo Zhou 2013/01/16 23:14:39 But why do we need is_in_container?
not at google - send to devlin 2013/01/17 00:11:49 So that GetCppType knows that if it's a pointer or
203 c.Append() 205 .Concat(self._GeneratePopulateVariableFromValue(
204 else: 206 type_.additional_properties,
205 c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out')) 207 '(&it.value())',
206 (c.Append('return true;') 208 'tmp',
207 .Eblock('}') 209 'false'))
208 ) 210 .Append('out->additional_properties[it.key()] = tmp;')
209 c.Substitute({'namespace': cpp_namespace, 'name': classname}) 211 .Eblock('}')
212 )
213 c.Append('return true;')
214 (c.Eblock('}')
215 .Substitute({'namespace': cpp_namespace, 'name': classname}))
210 return c 216 return c
211 217
212 def _GenerateTypePopulateProperty(self, prop, src, dst): 218 def _GenerateTypePopulateProperty(self, prop, src, dst):
213 """Generate the code to populate a single property in a type. 219 """Generate the code to populate a single property in a type.
214 220
215 src: base::DictionaryValue* 221 src: base::DictionaryValue*
216 dst: Type* 222 dst: Type*
217 """ 223 """
218 c = Code() 224 c = Code()
219 value_var = prop.unix_name + '_value' 225 value_var = prop.unix_name + '_value'
220 c.Append('const base::Value* %(value_var)s = NULL;') 226 c.Append('const base::Value* %(value_var)s = NULL;')
221 if prop.optional: 227 if prop.optional:
222 (c.Sblock( 228 (c.Sblock(
223 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {') 229 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {')
224 .Concat(self._GeneratePopulatePropertyFromValue( 230 .Concat(self._GeneratePopulatePropertyFromValue(
225 prop, value_var, dst, 'false'))) 231 prop, value_var, dst, 'false')))
226 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 232 underlying_type = self._type_helper.FollowRef(prop.type_)
233 if underlying_type.property_type == PropertyType.ENUM:
227 (c.Append('} else {') 234 (c.Append('} else {')
228 .Append('%%(dst)s->%%(name)s = %s;' % 235 .Append('%%(dst)s->%%(name)s = %s;' %
229 self._cpp_type_generator.GetEnumNoneValue(prop))) 236 self._type_helper.GetEnumNoneValue(prop.type_)))
230 c.Eblock('}') 237 c.Eblock('}')
231 else: 238 else:
232 (c.Append( 239 (c.Append(
233 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') 240 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))')
234 .Append(' return false;') 241 .Append(' return false;')
235 .Concat(self._GeneratePopulatePropertyFromValue( 242 .Concat(self._GeneratePopulatePropertyFromValue(
236 prop, value_var, dst, 'false')) 243 prop, value_var, dst, 'false'))
237 ) 244 )
238 c.Append() 245 c.Append()
239 c.Substitute({ 246 c.Substitute({
240 'value_var': value_var, 247 'value_var': value_var,
241 'key': prop.name, 248 'key': prop.name,
242 'src': src, 249 'src': src,
243 'dst': dst, 250 'dst': dst,
244 'name': prop.unix_name 251 'name': prop.unix_name
245 }) 252 })
246 return c 253 return c
247 254
248 def _GenerateTypeToValue(self, cpp_namespace, type_): 255 def _GenerateTypeToValue(self, cpp_namespace, type_):
249 """Generates a function that serializes the type into a 256 """Generates a function that serializes the type into a base::Value.
250 |base::DictionaryValue|. 257 E.g. for type "Foo" generates Foo::ToValue()
258 """
259 if type_.property_type == PropertyType.OBJECT:
260 return self._GenerateObjectTypeToValue(cpp_namespace, type_)
261 elif type_.property_type == PropertyType.CHOICES:
262 return self._GenerateChoiceTypeToValue(cpp_namespace, type_)
263 else:
264 raise ValueError("Unsupported propety type %s" % type_.type_)
Yoyo Zhou 2013/01/15 01:49:25 typo: property
not at google - send to devlin 2013/01/15 21:47:27 Done.
251 265
252 E.g. for type "Foo" generates Foo::ToValue() 266 def _GenerateObjectTypeToValue(self, cpp_namespace, type_):
267 """Generates a function that serializes an object-representing type
268 into a base::DictionaryValue.
253 """ 269 """
254 c = Code() 270 c = Code()
255 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' % 271 (c.Sblock('scoped_ptr<base::DictionaryValue> %s::ToValue() const {' %
256 cpp_namespace) 272 cpp_namespace)
257 .Append('scoped_ptr<base::DictionaryValue> value(' 273 .Append('scoped_ptr<base::DictionaryValue> value('
258 'new base::DictionaryValue());') 274 'new base::DictionaryValue());')
259 .Append() 275 .Append()
260 ) 276 )
277
261 for prop in type_.properties.values(): 278 for prop in type_.properties.values():
262 if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 279 if prop.optional:
263 c.Append('value->MergeDictionary(&%s);' % prop.unix_name) 280 # Optional enum values are generated with a NONE enum value.
264 else: 281 underlying_type = self._type_helper.FollowRef(prop.type_)
265 if prop.optional: 282 if underlying_type.property_type == PropertyType.ENUM:
266 if self._cpp_type_generator.IsEnumOrEnumRef(prop): 283 c.Sblock('if (%s != %s) {' %
267 c.Sblock('if (%s != %s) {' % 284 (prop.unix_name,
268 (prop.unix_name, 285 self._type_helper.GetEnumNoneValue(prop.type_)))
269 self._cpp_type_generator.GetEnumNoneValue(prop))) 286 else:
270 elif prop.type_ == PropertyType.CHOICES: 287 c.Sblock('if (%s.get()) {' % prop.unix_name)
271 c.Sblock('if (%s_type != %s) {' %
272 (prop.unix_name,
273 self._cpp_type_generator.GetEnumNoneValue(prop)))
274 else:
275 c.Sblock('if (%s.get()) {' % prop.unix_name)
276 288
277 if prop.type_ == prop.compiled_type: 289 # ANY is a base::Value which is abstract and cannot be a direct member, so
278 c.Append('value->SetWithoutPathExpansion("%s", %s);' % ( 290 # we always need to wrap it in a scoped_ptr.
279 prop.name, 291 is_optional_for_value = (prop.optional or
280 self._CreateValueFromProperty(prop, 'this->' + prop.unix_name))) 292 prop.type_.property_type == PropertyType.ANY)
281 else: 293 c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
282 conversion_src = 'this->' + prop.unix_name 294 prop.name,
283 if prop.optional: 295 self._CreateValueFromType(prop.type_,
284 conversion_src = '*' + conversion_src 296 'this->%s' % prop.unix_name,
285 (c.Append('%s %s;' % (self._cpp_type_generator.GetType(prop), 297 is_optional=is_optional_for_value)))
286 prop.unix_name)) 298
287 .Append(cpp_util.GenerateCompiledTypeToTypeConversion( 299 if prop.optional:
288 self._cpp_type_generator.GetReferencedProperty(prop), 300 c.Eblock('}');
289 conversion_src, 301
290 prop.unix_name) + ';') 302 if type_.additional_properties is not None:
291 .Append('value->SetWithoutPathExpansion("%s", %s);' % ( 303 # Non-copyable types will be wrapped in a linked_ptr for inclusion in
292 prop.unix_name, 304 # maps, so we need to unwrap them.
Yoyo Zhou 2013/01/15 01:49:25 Do you have to worry about enums or optionality he
not at google - send to devlin 2013/01/15 21:47:27 Optionality isn't an issue since this is a type, n
293 self._CreateValueFromProperty(prop, prop.unix_name))) 305 needs_unwrap = (
294 ) 306 not self._type_helper.IsCopyable(type_.additional_properties))
295 if prop.optional: 307
296 c.Eblock('}'); 308 (c.Sblock('for (std::map<std::string, %s>::const_iterator it =' %
297 (c.Append() 309 (self._type_helper.GetCppType(type_.additional_properties,
298 .Append('return value.Pass();') 310 is_in_container=True)))
311 .Append(' additional_properties.begin();')
312 .Append(' it != additional_properties.end(); ++it) {')
313 .Append('value->SetWithoutPathExpansion(it->first, %s);' %
314 self._CreateValueFromType(
315 type_.additional_properties,
316 '%sit->second' % ('*' if needs_unwrap else '',)))
Yoyo Zhou 2013/01/15 01:49:25 nit: don't need the ,
not at google - send to devlin 2013/01/15 21:47:27 Done. I swear there was a day when if you put pare
317 .Eblock('}')
318 )
319
320 return (c.Append()
321 .Append('return value.Pass();')
322 .Eblock('}'))
323
324 def _GenerateChoiceTypeToValue(self, cpp_namespace, type_):
325 """Generates a function that serializes a choice-representing type
326 into a base::Value.
327 """
328 c = Code()
329 c.Sblock('scoped_ptr<base::Value> %s::ToValue() const {' % cpp_namespace)
330 for choice in type_.choices:
331 choice_var = 'as_%s' % choice.unix_name
332 (c.Sblock('if (%s) {' % choice_var)
333 .Append('return scoped_ptr<base::Value>(%s);' %
334 self._CreateValueFromType(choice, '*%s' % choice_var))
335 .Eblock('}')
336 )
337 (c.Append('NOTREACHED() << "%s has no choices";' % type_.unix_name)
Yoyo Zhou 2013/01/15 01:49:25 This message is confusing because it could mean mu
not at google - send to devlin 2013/01/15 21:47:27 Done.
338 .Append('return scoped_ptr<base::Value>();')
299 .Eblock('}') 339 .Eblock('}')
300 ) 340 )
301 return c 341 return c
302 342
303 def _GenerateFunction(self, cpp_namespace, function): 343 def _GenerateFunction(self, function):
304 """Generates the definitions for function structs. 344 """Generates the definitions for function structs.
305 """ 345 """
306 c = Code() 346 c = Code()
307 347
348 # TODO(kalman): use function.unix_name not Classname.
349 function_namespace = cpp_util.Classname(function.name)
350 (c.Append('namespace %s {' % function_namespace)
351 .Append()
352 )
353
308 # Params::Populate function 354 # Params::Populate function
309 if function.params: 355 if function.params:
310 c.Concat(self._GeneratePropertyFunctions(cpp_namespace + '::Params', 356 c.Concat(self._GeneratePropertyFunctions('Params', function.params))
311 function.params)) 357 (c.Append('Params::Params() {}')
312 (c.Append('%(cpp_namespace)s::Params::Params() {}') 358 .Append('Params::~Params() {}')
313 .Append('%(cpp_namespace)s::Params::~Params() {}')
314 .Append() 359 .Append()
315 .Concat(self._GenerateFunctionParamsCreate(cpp_namespace, function)) 360 .Cblock(self._GenerateFunctionParamsCreate(function))
316 .Append()
317 ) 361 )
318 362
319 # Results::Create function 363 # Results::Create function
320 if function.callback: 364 if function.callback:
321 c.Concat(self._GenerateCreateCallbackArguments( 365 c.Concat(self._GenerateCreateCallbackArguments('Results',
322 "%s::Results" % cpp_namespace, function.callback)) 366 function.callback))
323 367
324 c.Substitute({'cpp_namespace': cpp_namespace}) 368 c.Append('} // namespace %s' % function_namespace)
325
326 return c 369 return c
327 370
328 def _CreateValueFromProperty(self, prop, var): 371 def _GenerateEvent(self, event):
329 """Creates a base::Value given a property. Generated code passes ownership 372 # TODO(kalman): use event.unix_name not Classname.
373 c = Code()
374 event_namespace = cpp_util.Classname(event.name)
375 (c.Append('namespace %s {' % event_namespace)
376 .Append()
377 .Cblock(self._GenerateCreateCallbackArguments(None, event))
378 .Append('} // namespace %s' % event_namespace)
379 )
380 return c
381
382 def _CreateValueFromType(self, type_, var, is_optional=False):
383 """Creates a base::Value given a type. Generated code passes ownership
330 to caller. 384 to caller.
331 385
332 var: variable or variable* 386 var: variable or variable*
333 387
334 E.g for std::string, generate base::Value::CreateStringValue(var) 388 E.g for std::string, generate base::Value::CreateStringValue(var)
335 """ 389 """
336 if prop.type_ == PropertyType.CHOICES: 390 underlying_type = self._type_helper.FollowRef(type_)
337 return 'Get%sChoiceValue().release()' % cpp_util.Classname(prop.name) 391 if (underlying_type.property_type == PropertyType.CHOICES or
338 elif self._IsObjectOrObjectRef(prop): 392 underlying_type.property_type == PropertyType.OBJECT):
339 if prop.optional: 393 if is_optional:
340 return '%s->ToValue().release()' % var 394 return '(%s)->ToValue().release()' % var
341 else: 395 else:
342 return '%s.ToValue().release()' % var 396 return '(%s).ToValue().release()' % var
343 elif prop.type_ == PropertyType.ANY: 397 elif (underlying_type.property_type == PropertyType.ANY or
344 return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var) 398 underlying_type.property_type == PropertyType.FUNCTION):
345 elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: 399 if is_optional:
346 return '%s.DeepCopy()' % var 400 vardot = '(%s)->' % var
347 elif prop.type_ == PropertyType.FUNCTION:
348 if prop.optional:
349 vardot = var + '->'
350 else: 401 else:
351 vardot = var + '.' 402 vardot = '(%s).' % var
352 return '%sDeepCopy()' % vardot 403 return '%sDeepCopy()' % vardot
353 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 404 elif underlying_type.property_type == PropertyType.ENUM:
354 return 'base::Value::CreateStringValue(ToString(%s))' % var 405 return 'base::Value::CreateStringValue(ToString(%s))' % var
355 elif prop.type_ == PropertyType.BINARY: 406 elif underlying_type.property_type == PropertyType.BINARY:
356 if prop.optional: 407 if is_optional:
357 vardot = var + '->' 408 vardot = var + '->'
358 else: 409 else:
359 vardot = var + '.' 410 vardot = var + '.'
360 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' % 411 return ('base::BinaryValue::CreateWithCopiedBuffer(%sdata(), %ssize())' %
361 (vardot, vardot)) 412 (vardot, vardot))
362 elif self._IsArrayOrArrayRef(prop): 413 elif underlying_type.property_type == PropertyType.ARRAY:
363 return '%s.release()' % self._util_cc_helper.CreateValueFromArray( 414 return '%s.release()' % self._util_cc_helper.CreateValueFromArray(
364 self._cpp_type_generator.GetReferencedProperty(prop), var, 415 underlying_type,
365 prop.optional) 416 var,
366 elif self._IsFundamentalOrFundamentalRef(prop): 417 is_optional)
367 # If prop.type != prop.compiled_type, then no asterisk is necessary 418 elif underlying_type.property_type.is_fundamental:
368 # because the target is a local variable and not a dereferenced scoped 419 if is_optional:
369 # pointer. The asterisk is instead prepended to conversion_src around line 420 var = '*%s' % var
370 # 273. 421 if underlying_type.property_type == PropertyType.STRING:
371 if prop.optional and prop.type_ == prop.compiled_type: 422 return 'new base::StringValue(%s)' % var
372 var = '*' + var 423 else:
373 prop = self._cpp_type_generator.GetReferencedProperty(prop); 424 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: 425 else:
381 raise NotImplementedError('Conversion of %s to base::Value not ' 426 raise NotImplementedError('Conversion of %s to base::Value not '
382 'implemented' % repr(prop.type_)) 427 'implemented' % repr(type_.type_))
383 428
384 def _GenerateParamsCheck(self, function, var): 429 def _GenerateParamsCheck(self, function, var):
385 """Generates a check for the correct number of arguments when creating 430 """Generates a check for the correct number of arguments when creating
386 Params. 431 Params.
387 """ 432 """
388 c = Code() 433 c = Code()
389 num_required = 0 434 num_required = 0
390 for param in function.params: 435 for param in function.params:
391 if not param.optional: 436 if not param.optional:
392 num_required += 1 437 num_required += 1
393 if num_required == len(function.params): 438 if num_required == len(function.params):
394 c.Append('if (%(var)s.GetSize() != %(total)d)') 439 c.Append('if (%(var)s.GetSize() != %(total)d)')
395 elif not num_required: 440 elif not num_required:
396 c.Append('if (%(var)s.GetSize() > %(total)d)') 441 c.Append('if (%(var)s.GetSize() > %(total)d)')
397 else: 442 else:
398 c.Append('if (%(var)s.GetSize() < %(required)d' 443 c.Append('if (%(var)s.GetSize() < %(required)d'
399 ' || %(var)s.GetSize() > %(total)d)') 444 ' || %(var)s.GetSize() > %(total)d)')
400 c.Append(' return scoped_ptr<Params>();') 445 c.Append(' return scoped_ptr<Params>();')
401 c.Substitute({ 446 c.Substitute({
402 'var': var, 447 'var': var,
403 'required': num_required, 448 'required': num_required,
404 'total': len(function.params), 449 'total': len(function.params),
405 }) 450 })
406 return c 451 return c
407 452
408 def _GenerateFunctionParamsCreate(self, cpp_namespace, function): 453 def _GenerateFunctionParamsCreate(self, function):
409 """Generate function to create an instance of Params. The generated 454 """Generate function to create an instance of Params. The generated
410 function takes a base::ListValue of arguments. 455 function takes a base::ListValue of arguments.
411 456
412 E.g for function "Bar", generate Bar::Params::Create() 457 E.g for function "Bar", generate Bar::Params::Create()
413 """ 458 """
414 c = Code() 459 c = Code()
415 (c.Append('// static') 460 (c.Append('// static')
416 .Sblock('scoped_ptr<%(cpp_namespace)s::Params> ' 461 .Sblock('scoped_ptr<Params> '
417 '%(cpp_namespace)s::Params::Create(const base::ListValue& args) {') 462 'Params::Create(const base::ListValue& args) {')
418 .Concat(self._GenerateParamsCheck(function, 'args')) 463 .Concat(self._GenerateParamsCheck(function, 'args'))
419 .Append('scoped_ptr<Params> params(new Params());') 464 .Append('scoped_ptr<Params> params(new Params());')
420 ) 465 )
421 c.Substitute({'cpp_namespace': cpp_namespace})
422 466
423 for param in function.params: 467 for param in function.params:
424 c.Concat(self._InitializePropertyToDefault(param, 'params')) 468 c.Concat(self._InitializePropertyToDefault(param, 'params'))
425 469
426 for i, param in enumerate(function.params): 470 for i, param in enumerate(function.params):
427 # Any failure will cause this function to return. If any argument is 471 # Any failure will cause this function to return. If any argument is
428 # incorrect or missing, those following it are not processed. Note that 472 # incorrect or missing, those following it are not processed. Note that
429 # for optional arguments, we allow missing arguments and proceed because 473 # for optional arguments, we allow missing arguments and proceed because
430 # there may be other arguments following it. 474 # there may be other arguments following it.
431 failure_value = 'scoped_ptr<Params>()' 475 failure_value = 'scoped_ptr<Params>()'
432 c.Append() 476 c.Append()
433 value_var = param.unix_name + '_value' 477 value_var = param.unix_name + '_value'
434 (c.Append('const base::Value* %(value_var)s = NULL;') 478 (c.Append('const base::Value* %(value_var)s = NULL;')
435 .Append('if (args.Get(%(i)s, &%(value_var)s) &&\n' 479 .Append('if (args.Get(%(i)s, &%(value_var)s) &&')
436 ' !%(value_var)s->IsType(base::Value::TYPE_NULL))') 480 .Sblock(' !%(value_var)s->IsType(base::Value::TYPE_NULL)) {')
437 .Sblock('{')
438 .Concat(self._GeneratePopulatePropertyFromValue( 481 .Concat(self._GeneratePopulatePropertyFromValue(
439 param, value_var, 'params', failure_value)) 482 param, value_var, 'params', failure_value))
440 .Eblock('}') 483 .Eblock('}')
441 ) 484 )
442 if not param.optional: 485 if not param.optional:
443 (c.Sblock('else {') 486 (c.Sblock('else {')
444 .Append('return %s;' % failure_value) 487 .Append('return %s;' % failure_value)
445 .Eblock('}') 488 .Eblock('}')
446 ) 489 )
447 c.Substitute({'value_var': value_var, 'i': i}) 490 c.Substitute({'value_var': value_var, 'i': i})
448 (c.Append() 491 (c.Append()
449 .Append('return params.Pass();') 492 .Append('return params.Pass();')
450 .Eblock('}') 493 .Eblock('}')
451 .Append() 494 .Append()
452 ) 495 )
453 496
454 return c 497 return c
455 498
456 def _GeneratePopulatePropertyFromValue( 499 def _GeneratePopulatePropertyFromValue(self,
457 self, prop, value_var, dst, failure_value, check_type=True): 500 prop,
458 """Generates code to populate a model.Property given a base::Value*. The 501 src_var,
459 existence of data inside the base::Value* is assumed so checks for existence 502 dst_class_var,
460 should be performed before the code this generates. 503 failure_value):
461 504 """Generates code to populate property |prop| of |dst_class_var| (a
462 prop: the property the code is populating. 505 pointer) from a Value*. See |_GeneratePopulateVariableFromValue| for
463 value_var: a base::Value* that should represent |prop|. 506 semantics.
464 dst: the object with |prop| as a member. 507 """
465 failure_value: the value to return if |prop| cannot be extracted from 508 return self._GeneratePopulateVariableFromValue(prop.type_,
466 |value_var| 509 src_var,
467 check_type: if true, will check if |value_var| is the correct 510 '%s->%s' % (dst_class_var,
468 base::Value::Type 511 prop.unix_name),
512 failure_value,
513 is_optional=prop.optional)
514
515 def _GeneratePopulateVariableFromValue(self,
516 type_,
517 src_var,
518 dst_var,
519 failure_value,
520 is_optional=False):
521 """Generates code to populate a variable |dst_var| of type |type_| from a
522 Value* at |src_var|. The Value* is assumed to be non-NULL. Generates a
523 failure return type of |failure_value|.
Yoyo Zhou 2013/01/15 01:49:25 Explain what the failure condition is.
not at google - send to devlin 2013/01/15 21:47:27 Done.
469 """ 524 """
470 c = Code() 525 c = Code()
471 c.Sblock('{') 526 c.Sblock('{')
472 527
473 if self._IsFundamentalOrFundamentalRef(prop): 528 underlying_type = self._type_helper.FollowRef(type_)
474 self._GenerateFundamentalOrFundamentalRefPopulate(c, prop, value_var, dst) 529
475 elif self._IsObjectOrObjectRef(prop): 530 if underlying_type.property_type.is_fundamental:
476 self._GenerateObjectOrObjectRefPopulate(c, prop) 531 if is_optional:
477 elif prop.type_ == PropertyType.FUNCTION: 532 (c.Append('%(cpp_type)s temp;')
478 self._GenerateFunctionPopulate(c, prop) 533 .Append('if (!%s)' % cpp_util.GetAsFundamentalValue(
479 elif prop.type_ == PropertyType.ANY: 534 self._type_helper.FollowRef(type_), src_var, '&temp'))
480 self._GenerateAnyPopulate(c, prop, value_var, dst) 535 .Append(' return %(failure_value)s;')
481 elif self._IsArrayOrArrayRef(prop): 536 .Append('%(dst_var)s.reset(new %(cpp_type)s(temp));')
482 self._GenerateArrayOrArrayRefPopulate(c, prop, dst) 537 )
483 elif prop.type_ == PropertyType.CHOICES: 538 else:
484 self._GenerateChoicePopulate(c, prop, value_var, dst, failure_value) 539 (c.Append('if (!%s)' % cpp_util.GetAsFundamentalValue(
485 elif self._cpp_type_generator.IsEnumOrEnumRef(prop): 540 self._type_helper.FollowRef(type_),
486 self._GenerateEnumPopulate(c, prop, value_var) 541 src_var,
487 elif prop.type_ == PropertyType.BINARY: 542 '&%s' % dst_var))
488 self._GenerateBinaryPopulate(c, prop) 543 .Append(' return %(failure_value)s;')
544 )
545 elif underlying_type.property_type == PropertyType.OBJECT:
546 if is_optional:
547 (c.Append('const base::DictionaryValue* dictionary = NULL;')
548 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))')
549 .Append(' return %(failure_value)s;')
550 .Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
551 .Append('if (!%(cpp_type)s::Populate(*dictionary, temp.get()))')
552 .Append(' return %(failure_value)s;')
553 .Append('%(dst_var)s = temp.Pass();')
554 )
555 else:
556 (c.Append('const base::DictionaryValue* dictionary = NULL;')
557 .Append('if (!%(src_var)s->GetAsDictionary(&dictionary))')
558 .Append(' return %(failure_value)s;')
559 .Append('if (!%(cpp_type)s::Populate(*dictionary, &%(dst_var)s))')
560 .Append(' return %(failure_value)s;')
561 )
562 elif underlying_type.property_type == PropertyType.FUNCTION:
563 if is_optional:
564 c.Append('%(dst_var)s.reset(new base::DictionaryValue());')
565 elif underlying_type.property_type == PropertyType.ANY:
566 c.Append('%(dst_var)s.reset(%(src_var)s->DeepCopy());')
567 elif underlying_type.property_type == PropertyType.ARRAY:
568 # util_cc_helper deals with optional and required arrays
569 (c.Append('const base::ListValue* list = NULL;')
570 .Append('if (!%(src_var)s->GetAsList(&list))')
571 .Append(' return %(failure_value)s;'))
572 item_type = underlying_type.item_type
573 if item_type.property_type == PropertyType.ENUM:
574 c.Concat(self._GenerateListValueToEnumArrayConversion(
575 item_type,
576 'list',
577 dst_var,
578 failure_value,
579 is_optional=is_optional))
580 else:
581 (c.Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList(
582 underlying_type,
583 'list',
584 dst_var,
585 is_optional))
586 .Append(' return %(failure_value)s;')
587 )
588 elif underlying_type.property_type == PropertyType.CHOICES:
589 if is_optional:
590 (c.Append('scoped_ptr<%(cpp_type)s> temp(new %(cpp_type)s());')
591 .Append('if (!%(cpp_type)s::Populate(*%(src_var)s, temp.get()))')
592 .Append(' return %(failure_value)s;')
593 .Append('%(dst_var)s = temp.Pass();')
594 )
595 else:
596 (c.Append('if (!%(cpp_type)s::Populate(*%(src_var)s, &%(dst_var)s))')
597 .Append(' return %(failure_value)s;')
598 )
599 elif underlying_type.property_type == PropertyType.ENUM:
600 c.Concat(self._GenerateStringToEnumConversion(type_,
601 src_var,
602 dst_var,
603 failure_value))
604 elif underlying_type.property_type == PropertyType.BINARY:
605 (c.Append('if (!%(src_var)s->IsType(%(value_type)s))')
606 .Append(' return %(failure_value)s;')
607 .Append('const base::BinaryValue* binary_value =')
608 .Append(' static_cast<const base::BinaryValue*>(%(src_var)s);')
609 )
610 if is_optional:
611 (c.Append('%(dst_var)s.reset(')
612 .Append(' new std::string(binary_value->GetBuffer(),')
613 .Append(' binary_value->GetSize()));')
614 )
615 else:
616 (c.Append('%(dst_var)s.assign(binary_value->GetBuffer(),')
617 .Append(' binary_value->GetSize());')
618 )
489 else: 619 else:
490 raise NotImplementedError(prop.type_) 620 raise NotImplementedError(type_)
491 c.Eblock('}') 621
492 sub = { 622 sub = {
493 'value_var': value_var, 623 'cpp_type': self._type_helper.GetCppType(type_),
494 'name': prop.unix_name, 624 'src_var': src_var,
495 'dst': dst, 625 'dst_var': dst_var,
496 'failure_value': failure_value, 626 'failure_value': failure_value,
497 } 627 }
498 if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): 628
499 sub['ctype'] = self._cpp_type_generator.GetType(prop) 629 if underlying_type.property_type not in (PropertyType.ANY,
500 sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType(prop) 630 PropertyType.CHOICES):
Yoyo Zhou 2013/01/15 01:49:25 nit: indent
not at google - send to devlin 2013/01/15 21:47:27 Done.
501 sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator 631 sub['value_type'] = cpp_util.GetValueType(underlying_type)
502 .GetReferencedProperty(prop).type_) 632
503 c.Substitute(sub) 633 return c.Eblock('}').Substitute(sub)
504 return c 634
505 635 def _GenerateListValueToEnumArrayConversion(self,
506 def _GenerateFundamentalOrFundamentalRefPopulate(self, 636 item_type,
507 c, 637 src_var,
508 prop, 638 dst_var,
509 value_var, 639 failure_value,
510 dst): 640 is_optional=False):
511 if prop.optional: 641 """Returns Code that converts a ListValue of string constants from
512 (c.Append('%(ctype)s temp;') 642 |src_var| into an array of enums of |type_| in |dst_var|. On failure,
513 .Append('if (!%s)' % 643 returns |failure_value|.
514 cpp_util.GetAsFundamentalValue( 644 """
515 self._cpp_type_generator.GetReferencedProperty(prop), 645 c = Code()
516 value_var, 646 accessor = '.'
517 '&temp')) 647 if is_optional:
518 .Append(' return %(failure_value)s;') 648 accessor = '->'
519 ) 649 c.Append('%s.reset(new std::vector<%s>);' % (
520 if prop.type_ != prop.compiled_type: 650 dst_var,
521 (c.Append('%(compiled_ctype)s temp2;') 651 self._type_helper.GetCppType(item_type,
522 .Append('if (!%s)' % 652 is_in_container=True)))
523 cpp_util.GenerateTypeToCompiledTypeConversion( 653 (c.Sblock('for (base::ListValue::const_iterator it = %s->begin(); '
524 self._cpp_type_generator.GetReferencedProperty(prop), 654 'it != %s->end(); ++it) {' % (src_var, src_var))
525 'temp', 655 .Append('%s tmp;' % self._type_helper.GetCppType(item_type))
526 'temp2')) 656 .Concat(self._GenerateStringToEnumConversion(item_type,
527 .Append(' return %(failure_value)s;') 657 '(*it)',
528 .Append('%(dst)s->%(name)s.reset(new %(compiled_ctype)s(temp2));') 658 'tmp',
529 ) 659 failure_value))
530 else: 660 .Append('%s%spush_back(tmp);' % (dst_var, accessor))
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('}') 661 .Eblock('}')
611 ) 662 )
612 (c.Append('default:') 663 return c
613 .Append(' return %(failure_value)s;') 664
614 ) 665 def _GenerateStringToEnumConversion(self,
615 c.Eblock('}') 666 type_,
616 667 src_var,
617 def _GenerateEnumPopulate(self, c, prop, value_var): 668 dst_var,
618 c.Sblock('{') 669 failure_value):
619 self._GenerateStringToEnumConversion(c, prop, value_var, 'enum_temp') 670 """Returns Code that converts a string type in |src_var| to an enum with
620 c.Append('%(dst)s->%(name)s = enum_temp;') 671 type |type_| in |dst_var|. On failure, returns |failure_value|.
Yoyo Zhou 2013/01/15 01:49:25 "on failure" should be a subordinate clause, other
not at google - send to devlin 2013/01/15 21:47:27 Done.
621 c.Eblock('}') 672 """
622 673 c = Code()
623 def _GenerateBinaryPopulate(self, c, prop): 674 enum_as_string = '%s_as_string' % type_.unix_name
624 (c.Append('if (!%(value_var)s->IsType(%(value_type)s))') 675 (c.Append('std::string %s;' % enum_as_string)
625 .Append(' return %(failure_value)s;') 676 .Append('if (!%s->GetAsString(&%s))' % (src_var, enum_as_string))
626 .Append('const base::BinaryValue* binary_value =') 677 .Append(' return %s;' % failure_value)
627 .Append(' static_cast<const base::BinaryValue*>(%(value_var)s);') 678 .Append('%s = Parse%s(%s);' % (dst_var,
628 ) 679 self._type_helper.GetCppType(type_),
629 if prop.optional: 680 enum_as_string))
630 (c.Append('%(dst)s->%(name)s.reset(') 681 .Append('if (%s == %s)' % (dst_var,
631 .Append(' new std::string(binary_value->GetBuffer(),') 682 self._type_helper.GetEnumNoneValue(type_)))
632 .Append(' binary_value->GetSize()));') 683 .Append(' return %s;' % failure_value)
633 ) 684 )
634 else: 685 return c
635 (c.Append('%(dst)s->%(name)s.assign(binary_value->GetBuffer(),') 686
636 .Append(' binary_value->GetSize());') 687 def _GeneratePropertyFunctions(self, namespace, params):
637 ) 688 """Generates the member functions for a list of parameters.
638 689 """
639 def _GenerateListValueToEnumArrayConversion(self, c, prop): 690 return self._GenerateTypes(namespace, (param.type_ for param in params))
640 """Appends code that converts a ListValue of string contstants to 691
641 an array of enums in dst. 692 def _GenerateTypes(self, namespace, types):
642 Leaves dst, name, and failure_value unsubstituted. 693 """Generates the member functions for a list of types.
643 694 """
644 c: the Code object that is being appended to. 695 c = Code()
645 prop: the property that the code is populating. 696 for type_ in types:
646 """ 697 c.Cblock(self._GenerateType(namespace, type_))
647 accessor = '.' 698 return c
648 if prop.optional: 699
649 c.Append('%(dst)s->%(name)s.reset(new std::vector<' + ( 700 def _GenerateEnumToString(self, cpp_namespace, type_):
650 self._cpp_type_generator.GetType(prop.item_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. 701 """Generates ToString() which gets the string representation of an enum.
756 """ 702 """
757 c = Code() 703 c = Code()
758 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 704 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
759 if use_namespace: 705
760 namespace = '%s::' % cpp_namespace 706 if cpp_namespace is not None:
761 else: 707 c.Append('// static')
762 namespace = '' 708 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace
763 709
764 (c.Append('// static') 710 c.Sblock('std::string %sToString(%s enum_param) {' %
765 .Sblock('std::string %(namespace)sToString(%(class)s enum_param) {')) 711 (maybe_namespace, classname))
766 enum_prop = self._cpp_type_generator.GetReferencedProperty(prop)
767 c.Sblock('switch (enum_param) {') 712 c.Sblock('switch (enum_param) {')
768 for enum_value in enum_prop.enum_values: 713 for enum_value in self._type_helper.FollowRef(type_).enum_values:
769 c.Concat(self._GenerateReturnCase( 714 (c.Append('case %s: ' % self._type_helper.GetEnumValue(type_, enum_value))
770 self._cpp_type_generator.GetEnumValue(prop, enum_value), 715 .Append(' return "%s";' % enum_value))
771 '"%s"' % enum_value)) 716 (c.Append('case %s:' % self._type_helper.GetEnumNoneValue(type_))
772 (c.Append('case %s:' % self._cpp_type_generator.GetEnumNoneValue(prop))
773 .Append(' return "";') 717 .Append(' return "";')
774 .Eblock('}') 718 .Eblock('}')
719 .Append('NOTREACHED();')
775 .Append('return "";') 720 .Append('return "";')
776 .Eblock('}') 721 .Eblock('}')
777 .Substitute({ 722 )
778 'namespace': namespace, 723 return c
779 'class': classname 724
780 })) 725 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 726 """Generates FromClassNameString() which gets an enum from its string
785 representation. 727 representation.
786 """ 728 """
787 c = Code() 729 c = Code()
788 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(prop.name)) 730 classname = cpp_util.Classname(schema_util.StripSchemaNamespace(type_.name))
789 if use_namespace: 731
790 namespace = '%s::' % cpp_namespace 732 if cpp_namespace is not None:
791 else: 733 c.Append('// static')
792 namespace = '' 734 maybe_namespace = '' if cpp_namespace is None else '%s::' % cpp_namespace
793 735
794 (c.Append('// static') 736 c.Sblock('%s%s %sParse%s(const std::string& enum_string) {' %
795 .Sblock('%(namespace)s%(class)s' 737 (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( 738 for i, enum_value in enumerate(
800 self._cpp_type_generator.GetReferencedProperty(prop).enum_values): 739 self._type_helper.FollowRef(type_).enum_values):
801 # This is broken up into all ifs with no else ifs because we get 740 # This is broken up into all ifs with no else ifs because we get
802 # "fatal error C1061: compiler limit : blocks nested too deeply" 741 # "fatal error C1061: compiler limit : blocks nested too deeply"
803 # on Windows. 742 # on Windows.
804 (c.Append('if (enum_string == "%s")' % enum_value) 743 (c.Append('if (enum_string == "%s")' % enum_value)
805 .Append(' return %s;' % 744 .Append(' return %s;' %
806 self._cpp_type_generator.GetEnumValue(prop, enum_value))) 745 self._type_helper.GetEnumValue(type_, enum_value)))
807 (c.Append('return %s;' % 746 (c.Append('return %s;' % self._type_helper.GetEnumNoneValue(type_))
808 self._cpp_type_generator.GetEnumNoneValue(prop))
809 .Eblock('}') 747 .Eblock('}')
810 .Substitute({ 748 )
811 'namespace': namespace, 749 return c
812 'class': classname 750
813 })) 751 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. 752 """Generate all functions to create Value parameters for a callback.
854 753
855 E.g for function "Bar", generate Bar::Results::Create 754 E.g for function "Bar", generate Bar::Results::Create
856 E.g for event "Baz", generate Baz::Create 755 E.g for event "Baz", generate Baz::Create
857 756
858 function_scope: the function scope path, e.g. Foo::Bar for the function 757 function_scope: the function scope path, e.g. Foo::Bar for the function
859 Foo::Bar::Baz(). 758 Foo::Bar::Baz(). May be None if there is no function scope.
860 callback: the Function object we are creating callback arguments for. 759 callback: the Function object we are creating callback arguments for.
861 generate_to_json: Generate a ToJson method.
862 """ 760 """
863 c = Code() 761 c = Code()
864 params = callback.params 762 params = callback.params
865 expanded_params = self._cpp_type_generator.ExpandParams(params) 763 c.Concat(self._GeneratePropertyFunctions(function_scope, params))
866 c.Concat(self._GeneratePropertyFunctions(function_scope, expanded_params)) 764
867 765 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s'
868 param_lists = self._cpp_type_generator.GetAllPossibleParameterLists(params) 766 'Create(%(declaration_list)s) {')
869 for param_list in param_lists: 767 .Append('scoped_ptr<base::ListValue> create_results('
870 (c.Sblock('scoped_ptr<base::ListValue> %(function_scope)s::' 768 'new base::ListValue());')
871 'Create(%(declaration_list)s) {') 769 )
872 .Append('scoped_ptr<base::ListValue> create_results(' 770 declaration_list = []
873 'new base::ListValue());') 771 for param in params:
874 ) 772 declaration_list.append(cpp_util.GetParameterDeclaration(
875 declaration_list = [] 773 param, self._type_helper.GetCppType(param.type_)))
876 for param in param_list: 774 c.Append('create_results->Append(%s);' %
877 # We treat this argument as 'required' to avoid wrapping it in a 775 self._CreateValueFromType(param.type_, param.unix_name))
878 # scoped_ptr if it's optional. 776 c.Append('return create_results.Pass();')
879 param_copy = param.Copy() 777 c.Eblock('}')
880 param_copy.optional = False 778 c.Substitute({
881 declaration_list.append("const %s" % cpp_util.GetParameterDeclaration( 779 'function_scope': ('%s::' % function_scope) if function_scope else '',
882 param_copy, self._cpp_type_generator.GetCompiledType(param_copy))) 780 'declaration_list': ', '.join(declaration_list),
883 param_name = param_copy.unix_name 781 'param_names': ', '.join(param.unix_name for param in params)
884 if param_copy.type_ != param_copy.compiled_type: 782 })
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 783 return c
917 784
918 def _InitializePropertyToDefault(self, prop, dst): 785 def _InitializePropertyToDefault(self, prop, dst):
919 """Initialize a model.Property to its default value inside an object. 786 """Initialize a model.Property to its default value inside an object.
920 787
921 E.g for optional enum "state", generate dst->state = STATE_NONE; 788 E.g for optional enum "state", generate dst->state = STATE_NONE;
922 789
923 dst: Type* 790 dst: Type*
924 """ 791 """
925 c = Code() 792 c = Code()
926 if (self._cpp_type_generator.IsEnumOrEnumRef(prop) or 793 underlying_type = self._type_helper.FollowRef(prop.type_)
927 prop.type_ == PropertyType.CHOICES): 794 if (underlying_type.property_type == PropertyType.ENUM and
928 if prop.optional: 795 prop.optional):
929 prop_name = prop.unix_name 796 c.Append('%s->%s = %s;' % (
930 if prop.type_ == PropertyType.CHOICES: 797 dst,
931 prop_name = prop.unix_name + '_type' 798 prop.unix_name,
932 c.Append('%s->%s = %s;' % ( 799 self._type_helper.GetEnumNoneValue(prop.type_)))
933 dst,
934 prop_name,
935 self._cpp_type_generator.GetEnumNoneValue(prop)))
936 return c 800 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

Powered by Google App Engine
This is Rietveld 408576698