OLD | NEW |
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 model import PropertyType | 5 from model import PropertyType |
6 import code | 6 import code |
7 import cpp_util | 7 import cpp_util |
| 8 import util_cc_helper |
8 | 9 |
9 class CCGenerator(object): | 10 class CCGenerator(object): |
10 """A .cc generator for a namespace. | 11 """A .cc generator for a namespace. |
11 """ | 12 """ |
12 def __init__(self, namespace, cpp_type_generator): | 13 def __init__(self, namespace, cpp_type_generator): |
13 self._cpp_type_generator = cpp_type_generator | 14 self._cpp_type_generator = cpp_type_generator |
14 self._namespace = namespace | 15 self._namespace = namespace |
15 self._target_namespace = ( | 16 self._target_namespace = ( |
16 self._cpp_type_generator.GetCppNamespaceName(self._namespace)) | 17 self._cpp_type_generator.GetCppNamespaceName(self._namespace)) |
| 18 self._util_cc_helper = ( |
| 19 util_cc_helper.UtilCCHelper(self._cpp_type_generator)) |
17 | 20 |
18 def Generate(self): | 21 def Generate(self): |
19 """Generates a code.Code object with the .cc for a single namespace. | 22 """Generates a code.Code object with the .cc for a single namespace. |
20 """ | 23 """ |
21 c = code.Code() | 24 c = code.Code() |
22 (c.Append(cpp_util.CHROMIUM_LICENSE) | 25 (c.Append(cpp_util.CHROMIUM_LICENSE) |
23 .Append() | 26 .Append() |
24 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) | 27 .Append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file) |
25 .Append() | 28 .Append() |
26 .Append('#include "tools/json_schema_compiler/util.h"') | 29 .Append(self._util_cc_helper.GetIncludePath()) |
27 .Append('#include "%s/%s.h"' % | 30 .Append('#include "%s/%s.h"' % |
28 (self._namespace.source_file_dir, self._target_namespace)) | 31 (self._namespace.source_file_dir, self._namespace.name)) |
29 .Append() | 32 ) |
30 .Concat(self._cpp_type_generator.GetCppNamespaceStart()) | 33 includes = self._cpp_type_generator.GenerateIncludes() |
| 34 if not includes.IsEmpty(): |
| 35 (c.Concat(includes) |
| 36 .Append() |
| 37 ) |
| 38 |
| 39 (c.Append() |
| 40 .Concat(self._cpp_type_generator.GetRootNamespaceStart()) |
| 41 .Concat(self._cpp_type_generator.GetNamespaceStart()) |
31 .Append() | 42 .Append() |
32 .Append('//') | 43 .Append('//') |
33 .Append('// Types') | 44 .Append('// Types') |
34 .Append('//') | 45 .Append('//') |
35 .Append() | 46 .Append() |
36 ) | 47 ) |
37 for type_ in self._namespace.types.values(): | 48 for type_ in self._namespace.types.values(): |
38 (c.Concat(self._GenerateType(type_)) | 49 (c.Concat(self._GenerateType(type_.name, type_)) |
39 .Append() | 50 .Append() |
40 ) | 51 ) |
41 (c.Append('//') | 52 (c.Append('//') |
42 .Append('// Functions') | 53 .Append('// Functions') |
43 .Append('//') | 54 .Append('//') |
44 .Append() | 55 .Append() |
45 ) | 56 ) |
46 for function in self._namespace.functions.values(): | 57 for function in self._namespace.functions.values(): |
47 (c.Concat(self._GenerateFunction(function)) | 58 (c.Concat(self._GenerateFunction(function)) |
48 .Append() | 59 .Append() |
49 ) | 60 ) |
50 (c.Concat(self._cpp_type_generator.GetCppNamespaceEnd()) | 61 (c.Concat(self._cpp_type_generator.GetNamespaceEnd()) |
| 62 .Concat(self._cpp_type_generator.GetRootNamespaceEnd()) |
51 .Append() | 63 .Append() |
52 ) | 64 ) |
53 # TODO(calamity): Events | 65 # TODO(calamity): Events |
54 return c | 66 return c |
55 | 67 |
56 def _GenerateType(self, type_): | 68 def _GenerateType(self, cpp_namespace, type_, serializable=True): |
57 """Generates the function definitions for a type. | 69 """Generates the function definitions for a type. |
58 """ | 70 """ |
| 71 classname = cpp_util.Classname(type_.name) |
59 c = code.Code() | 72 c = code.Code() |
60 | 73 |
61 (c.Append('%(classname)s::%(classname)s() {}') | 74 (c.Append('%(namespace)s::%(classname)s() {}') |
62 .Append('%(classname)s::~%(classname)s() {}') | 75 .Append('%(namespace)s::~%(classname)s() {}') |
63 .Append() | 76 .Append() |
64 ) | 77 ) |
65 c.Substitute({'classname': type_.name}) | 78 c.Substitute({'classname': classname, 'namespace': cpp_namespace}) |
66 | 79 |
67 c.Concat(self._GenerateTypePopulate(type_)) | 80 c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)) |
68 c.Append() | 81 c.Append() |
69 # TODO(calamity): deal with non-serializable | 82 if serializable: |
70 c.Concat(self._GenerateTypeTovalue(type_)) | 83 c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)) |
71 c.Append() | 84 c.Append() |
72 | 85 |
73 return c | 86 return c |
74 | 87 |
75 def _GenerateTypePopulate(self, type_): | 88 def _GenerateTypePopulate(self, cpp_namespace, type_): |
76 """Generates the function for populating a type given a pointer to it. | 89 """Generates the function for populating a type given a pointer to it. |
77 """ | 90 """ |
| 91 classname = cpp_util.Classname(type_.name) |
78 c = code.Code() | 92 c = code.Code() |
79 (c.Append('// static') | 93 (c.Append('// static') |
80 .Sblock('bool %(name)s::Populate(const Value& value, %(name)s* out) {') | 94 .Sblock('bool %(namespace)s::Populate(const Value& value, %(name)s* out) {
') |
81 .Append('if (!value.IsType(Value::TYPE_DICTIONARY))') | 95 .Append('if (!value.IsType(Value::TYPE_DICTIONARY))') |
82 .Append(' return false;') | 96 .Append(' return false;') |
83 .Append('const DictionaryValue* dict = ' | 97 .Append('const DictionaryValue* dict = ' |
84 'static_cast<const DictionaryValue*>(&value);') | 98 'static_cast<const DictionaryValue*>(&value);') |
85 .Append() | 99 .Append() |
86 ) | 100 ) |
87 c.Substitute({'name': type_.name}) | 101 c.Substitute({'namespace': cpp_namespace, 'name': classname}) |
88 | 102 |
89 # TODO(calamity): this handle single PropertyType.REF properties. | 103 # TODO(calamity): this handle single PropertyType.REF properties. |
90 # add ALL the types | 104 # add ALL the types |
91 for prop in type_.properties.values(): | 105 for prop in type_.properties.values(): |
92 sub = {'name': prop.name} | 106 dst = 'out->' + prop.unix_name |
| 107 src = 'dict' |
93 if prop.type_ == PropertyType.ARRAY: | 108 if prop.type_ == PropertyType.ARRAY: |
94 if prop.item_type.type_ == PropertyType.REF: | 109 populate_line = self._util_cc_helper.GetArray(prop, src, prop.name, dst) |
95 if prop.optional: | 110 else: |
96 (c.Append('if (!json_schema_compiler::util::' | 111 if prop.optional: |
97 'GetOptionalTypes<%(type)s>(*dict,') | 112 dst = dst + '.get()' |
98 .Append(' "%(name)s", &out->%(name)s))') | |
99 .Append(' return false;') | |
100 ) | |
101 else: | |
102 (c.Append('if (!json_schema_compiler::util::' | |
103 'GetTypes<%(type)s>(*dict,') | |
104 .Append(' "%(name)s", &out->%(name)s))') | |
105 .Append(' return false;') | |
106 ) | |
107 sub['type'] = self._cpp_type_generator.GetType(prop.item_type, | |
108 pad_for_generics=True) | |
109 elif prop.item_type.type_ == PropertyType.STRING: | |
110 if prop.optional: | |
111 (c.Append('if (!json_schema_compiler::util::GetOptionalStrings' | |
112 '(*dict, "%(name)s", &out->%(name)s))') | |
113 .Append(' return false;') | |
114 ) | |
115 else: | |
116 (c.Append('if (!json_schema_compiler::util::GetStrings' | |
117 '(*dict, "%(name)s", &out->%(name)s))') | |
118 .Append(' return false;') | |
119 ) | |
120 else: | 113 else: |
121 raise NotImplementedError(prop.item_type.type_) | 114 dst = '&' + dst |
122 elif prop.type_.is_fundamental: | 115 if prop.type_.is_fundamental: |
123 c.Append('if (!dict->%s)' % | 116 populate_line = cpp_util.GetFundamentalValue(prop, src, prop.name, dst
) |
124 cpp_util.GetFundamentalValue(prop, '&out->%s' % prop.name)) | 117 elif prop.type_ == PropertyType.REF or prop.type_ == PropertyType.OBJECT
: |
125 c.Append(' return false;') | 118 populate_line = '%(ctype)s::Populate(*%(src)s, %(dst)s)' % { |
| 119 'src': src, 'dst': dst, |
| 120 'ctype': self._cpp_type_generator.GetType(prop) |
| 121 } |
| 122 if prop.optional: |
| 123 (c.Append('out->%s.reset(new %s);' % (prop.unix_name, self._cpp_type_gen
erator.GetType(prop))) |
| 124 .Append('%s;' % populate_line) |
| 125 ) |
126 else: | 126 else: |
127 raise NotImplementedError(prop.type_) | 127 (c.Append('if(!%s)' % populate_line) |
128 c.Substitute(sub) | 128 .Append(' return false;') |
| 129 ) |
129 (c.Append('return true;') | 130 (c.Append('return true;') |
130 .Eblock('}') | 131 .Eblock('}') |
131 ) | 132 ) |
132 return c | 133 return c |
133 | 134 |
134 def _GenerateTypeTovalue(self, type_): | 135 def _GenerateTypeToValue(self, cpp_namespace, type_): |
135 """Generates a function that serializes the type into a |DictionaryValue|. | 136 """Generates a function that serializes the type into a |DictionaryValue|. |
136 """ | 137 """ |
137 c = code.Code() | 138 c = code.Code() |
138 (c.Sblock('DictionaryValue* %s::ToValue() const {' % type_.name) | 139 (c.Sblock('DictionaryValue* %s::ToValue() const {' % cpp_namespace) |
139 .Append('DictionaryValue* value = new DictionaryValue();') | 140 .Append('DictionaryValue* value = new DictionaryValue();') |
140 .Append() | 141 .Append() |
141 ) | 142 ) |
142 name = type_.name.lower() | |
143 for prop in type_.properties.values(): | 143 for prop in type_.properties.values(): |
144 prop_name = name + '_' + prop.name if name else prop.name | 144 prop_name = prop.unix_name |
145 this_var = prop.name | 145 c.Concat(self._CreateValueFromProperty(prop_name, prop, prop_name, 'value'
)) |
146 c.Concat(self._CreateValueFromProperty(prop_name, prop, this_var)) | |
147 (c.Append() | 146 (c.Append() |
148 .Append('return value;') | 147 .Append('return value;') |
149 .Eblock('}') | 148 .Eblock('}') |
150 ) | 149 ) |
151 return c | 150 return c |
152 | 151 |
153 # TODO(calamity): object and choices prop types | 152 # TODO(calamity): object and choices prop types |
154 def _CreateValueFromProperty(self, name, prop, var): | 153 def _CreateValueFromProperty(self, name, prop, var, dst): |
155 """Generates code to serialize a single property in a type. | 154 """Generates code to serialize a single property in a type. |
156 """ | 155 """ |
157 c = code.Code() | 156 c = code.Code() |
158 if prop.type_.is_fundamental: | 157 if prop.type_ == PropertyType.ARRAY: |
159 c.Append('Value* %s_value = %s;' % | 158 c.Append('%s;' % self._util_cc_helper.SetArray(prop, var, prop.name, dst)) |
160 (name, cpp_util.CreateFundamentalValue(prop, var))) | |
161 elif prop.type_ == PropertyType.ARRAY: | |
162 if prop.item_type.type_ == PropertyType.STRING: | |
163 if prop.optional: | |
164 c.Append('json_schema_compiler::util::' | |
165 'SetOptionalStrings(%s, "%s", value);' % (var, prop.name)) | |
166 else: | |
167 c.Append('json_schema_compiler::util::' | |
168 'SetStrings(%s, "%s", value);' % (var, prop.name)) | |
169 else: | |
170 item_name = name + '_single' | |
171 (c.Append('ListValue* %(name)s_value = new ListValue();') | |
172 .Append('for (%(it_type)s::iterator it = %(var)s->begin();') | |
173 .Sblock(' it != %(var)s->end(); ++it) {') | |
174 .Concat(self._CreateValueFromProperty(item_name, prop.item_type, | |
175 '*it')) | |
176 .Append('%(name)s_value->Append(%(prop_val)s_value);') | |
177 .Eblock('}') | |
178 ) | |
179 c.Substitute( | |
180 {'it_type': self._cpp_type_generator.GetType(prop), | |
181 'name': name, 'var': var, 'prop_val': item_name}) | |
182 elif prop.type_ == PropertyType.REF: | |
183 c.Append('Value* %s_value = %s.ToValue();' % (name, var)) | |
184 else: | 159 else: |
185 raise NotImplementedError | 160 c.Append('%s->SetWithoutPathExpansion("%s", %s);' % |
| 161 (dst, prop.name, cpp_util.CreateValueFromSingleProperty(prop, var))) |
186 return c | 162 return c |
187 | 163 |
188 def _GenerateFunction(self, function): | 164 def _GenerateFunction(self, function): |
189 """Generates the definitions for function structs. | 165 """Generates the definitions for function structs. |
190 """ | 166 """ |
191 classname = cpp_util.CppName(function.name) | 167 classname = cpp_util.Classname(function.name) |
192 c = code.Code() | 168 c = code.Code() |
193 | 169 |
194 # Params::Populate function | 170 # Params::Populate function |
195 if function.params: | 171 if function.params: |
| 172 for param in function.params: |
| 173 if param.type_ == PropertyType.OBJECT: |
| 174 param_namespace = '%s::Params::%s' % (classname, cpp_util.Classname(pa
ram.name)) |
| 175 c.Concat(self._GenerateType(param_namespace, param, serializable=False
)) |
| 176 c.Append() |
196 (c.Append('%(name)s::Params::Params() {}') | 177 (c.Append('%(name)s::Params::Params() {}') |
197 .Append('%(name)s::Params::~Params() {}') | 178 .Append('%(name)s::Params::~Params() {}') |
198 .Append() | 179 .Append() |
199 .Concat(self._GenerateFunctionParamsCreate(function)) | 180 .Concat(self._GenerateFunctionParamsCreate(function)) |
200 .Append() | 181 .Append() |
201 ) | 182 ) |
202 | 183 |
203 # Result::Create function | 184 # Result::Create function |
204 c.Concat(self._GenerateFunctionResultCreate(function)) | 185 c.Concat(self._GenerateFunctionResultCreate(function)) |
205 | 186 |
206 c.Substitute({'name': classname}) | 187 c.Substitute({'name': classname}) |
207 | 188 |
208 return c | 189 return c |
209 | 190 |
210 def _GenerateFunctionParamsCreate(self, function): | 191 def _GenerateFunctionParamsCreate(self, function): |
211 """Generate function to create an instance of Params given a pointer. | 192 """Generate function to create an instance of Params given a pointer. |
212 """ | 193 """ |
213 classname = cpp_util.CppName(function.name) | 194 classname = cpp_util.Classname(function.name) |
214 c = code.Code() | 195 c = code.Code() |
215 (c.Append('// static') | 196 (c.Append('// static') |
216 .Sblock('scoped_ptr<%(classname)s::Params> %(classname)s::Params::Create' | 197 .Sblock('scoped_ptr<%(classname)s::Params> %(classname)s::Params::Create' |
217 '(const ListValue& args) {') | 198 '(const ListValue& args) {') |
218 .Append('if (args.GetSize() != %d)' % len(function.params)) | 199 #.Append('if (args.GetSize() != %d)' % len(function.params)) |
219 .Append(' return scoped_ptr<Params>();') | 200 #.Append(' return scoped_ptr<Params>();') |
220 .Append() | 201 .Append() |
221 .Append('scoped_ptr<Params> params(new Params());') | 202 .Append('scoped_ptr<Params> params(new Params());') |
222 ) | 203 ) |
223 c.Substitute({'classname': classname}) | 204 c.Substitute({'classname': classname}) |
224 | 205 |
225 # TODO(calamity): generalize, needs to move to function to do populates for | 206 # TODO(calamity): generalize, needs to move to function to do populates for |
226 # wider variety of args | 207 # wider variety of args |
227 for i, param in enumerate(function.params): | 208 for i, param in enumerate(function.params): |
228 sub = {'name': param.name, 'pos': i} | 209 dst = 'params->' + param.unix_name |
| 210 if param.optional: |
| 211 return_line = ' return params.Pass();' |
| 212 else: |
| 213 return_line = ' return scoped_ptr<Params>();' |
229 c.Append() | 214 c.Append() |
230 # TODO(calamity): Make valid for not just objects | 215 param_var = param.unix_name + '_param' |
231 c.Append('DictionaryValue* %(name)s_param = NULL;') | 216 if param.type_ == PropertyType.ARRAY: |
232 c.Append('if (!args.GetDictionary(%(pos)d, &%(name)s_param))') | 217 (c.Append('ListValue* %(var)s = NULL;') |
233 c.Append(' return scoped_ptr<Params>();') | 218 .Append('if (!args.GetList(%(index)d, &%(var)s))') |
234 if param.type_ == PropertyType.REF: | 219 .Append(return_line) |
235 c.Append('if (!%(ctype)s::Populate(*%(name)s_param, ' | 220 .Append('if (!%s)' % self._util_cc_helper.GetArrayFromList( |
236 '¶ms->%(name)s))') | 221 param, param_var, 'params->%s' % param.unix_name)) |
237 c.Append(' return scoped_ptr<Params>();') | 222 .Append(return_line) |
238 sub['ctype'] = self._cpp_type_generator.GetType(param) | 223 ) |
239 elif param.type_.is_fundamental: | 224 c.Substitute({'var': param_var, 'index': i}) |
240 raise NotImplementedError('Fundamental types are unimplemented') | |
241 elif param.type_ == PropertyType.OBJECT: | |
242 c.Append('if (!%(ctype)s::Populate(*%(name)s_param, ' | |
243 '¶ms->%(name)s))') | |
244 c.Append(' return scoped_ptr<Params>();') | |
245 sub['ctype'] = self._cpp_type_generator.GetType(param) | |
246 elif param.type_ == PropertyType.CHOICES: | |
247 raise NotImplementedError('Choices is unimplemented') | |
248 else: | 225 else: |
249 raise NotImplementedError(param.type_) | 226 if param.optional: |
250 c.Substitute(sub) | 227 dst = dst + '.get()' |
| 228 else: |
| 229 dst = '&' + dst |
| 230 if param.type_ == PropertyType.REF or param.type_ == PropertyType.OBJECT
: |
| 231 (c.Append('DictionaryValue* %s = NULL;' % param_var) |
| 232 .Append('if (!args.GetDictionary(%d, &%s))' % (i, param_var)) |
| 233 .Append(return_line) |
| 234 ) |
| 235 if param.optional: |
| 236 c.Append('params->%s.reset(new %s());' % (param.unix_name, cpp_util.
Classname(param.name))) |
| 237 (c.Append('if(!%(ctype)s::Populate(*%(var)s, %(dst)s))' % { |
| 238 'var': param_var, 'dst': dst, |
| 239 'ctype': self._cpp_type_generator.GetType(param) |
| 240 }) |
| 241 .Append(return_line) |
| 242 ) |
| 243 elif param.type_.is_fundamental: |
| 244 (c.Append('if(!%s)' % cpp_util.GetValueFromList(param, 'args', i, dst
)) |
| 245 .Append(return_line) |
| 246 ) |
251 c.Append() | 247 c.Append() |
252 c.Append('return params.Pass();') | 248 c.Append('return params.Pass();') |
253 c.Eblock('}') | 249 c.Eblock('}') |
254 | 250 |
255 return c | 251 return c |
256 | 252 |
257 def _GenerateFunctionResultCreate(self, function): | 253 def _GenerateFunctionResultCreate(self, function): |
258 """Generate function to create a Result given the return value. | 254 """Generate function to create a Result given the return value. |
259 """ | 255 """ |
260 classname = cpp_util.CppName(function.name) | 256 classname = cpp_util.Classname(function.name) |
261 c = code.Code() | 257 c = code.Code() |
262 c.Append('// static') | 258 c.Append('// static') |
263 param = function.callback.param | 259 params = function.callback.params |
264 arg = '' | 260 args = [] |
265 if param: | 261 |
266 if param.type_ == PropertyType.REF: | 262 if not params: |
267 arg = 'const %(type)s& %(name)s' | 263 (c.Append('Value* %s::Result::Create() {' % classname) |
268 else: | 264 .Append(' return Value::CreateNullValue();') |
| 265 .Append('}') |
| 266 ) |
| 267 else: |
| 268 for param in params: |
| 269 sub = { |
| 270 'type': self._cpp_type_generator.GetType(param), |
| 271 'name': param.unix_name, |
| 272 } |
269 arg = 'const %(type)s %(name)s' | 273 arg = 'const %(type)s %(name)s' |
270 arg = arg % { | 274 if param.type_ == PropertyType.REF: |
271 'type': self._cpp_type_generator.GetType(param), | 275 arg = 'const %(type)s& %(name)s' |
272 'name': param.name | 276 arg = arg % sub |
273 } | 277 if param and param.description: |
274 c.Sblock('Value* %(classname)s::Result::Create(%(arg)s) {') | 278 c.Comment(param.description) |
275 sub = {'classname': classname, 'arg': arg} | 279 c.Sblock('Value* %(classname)s::Result::Create(%(arg)s) {') |
276 # TODO(calamity): Choices | 280 sub = {'classname': classname, 'arg': arg} |
277 if not param: | 281 if param.type_ == PropertyType.ARRAY: |
278 c.Append('return Value::CreateNullValue();') | 282 (c.Append('ListValue* l = new ListValue();') |
279 else: | 283 .Append('for (' + self._cpp_type_generator.GetType(param) + |
280 sub['argname'] = param.name | 284 '::const_iterator it = %(var)s.begin(); it != %(var)s.end(); ++i
t) {') |
281 if param.type_.is_fundamental: | 285 .Append(' l->Append(%s);' % cpp_util.CreateValueFromSingleProperty(
param.item_type, '(**it)')) |
282 c.Append('return %s;' % | 286 .Append('}') |
283 cpp_util.CreateFundamentalValue(param, param.name)) | 287 .Append('return l;') |
284 elif param.type_ == PropertyType.REF: | 288 ) |
285 c.Append('return %(argname)s.ToValue();') | 289 sub['var'] = param.unix_name |
286 elif param.type_ == PropertyType.OBJECT: | 290 else: |
287 raise NotImplementedError('Objects not implemented') | 291 c.Append('return %s;' % cpp_util.CreateValueFromSingleProperty(param,
param.unix_name)) |
288 elif param.type_ == PropertyType.ARRAY: | 292 c.Substitute(sub) |
289 raise NotImplementedError('Arrays not implemented') | 293 c.Eblock('}') |
290 else: | 294 |
291 raise NotImplementedError(param.type_) | |
292 c.Substitute(sub) | |
293 c.Eblock('}') | |
294 return c | 295 return c |
OLD | NEW |