OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 from model import PropertyType | |
6 import code | |
7 import cpp_type_generator | |
8 import cpp_util | |
9 | |
10 class CCGenerator(object): | |
Yoyo Zhou
2012/01/19 02:19:40
General comment: have a read through the style gui
| |
11 """A .cc generator for a namespace. | |
12 """ | |
13 def __init__(self, namespace, model, root_namespace): | |
14 self.__cpp_type_generator = cpp_type_generator.CppTypeGenerator( | |
15 namespace, model) | |
16 self.__namespace = namespace | |
17 self.__root_namespace = root_namespace | |
18 | |
19 def generate(self): | |
20 """Generates a code.Code object with the .cc for a single namespace. | |
21 """ | |
22 target_namespace = self.__namespace.target_namespace | |
23 c = code.Code() | |
24 (c.append(cpp_util.CHROMIUM_LICENSE) | |
25 .append() | |
26 .append(cpp_util.GENERATED_FILE_MESSAGE % self.__namespace.source_file) | |
27 .append() | |
28 .append('#include "tools/json_schema_compiler/util.h"') | |
29 .append('#include "%s/%s.h"' % | |
30 (self.__namespace.source_file_dir, target_namespace)) | |
31 .append() | |
32 .append('namespace %s {' % self.__root_namespace) | |
33 .append('namespace %s {' % target_namespace) | |
34 .append() | |
35 .append('//') | |
36 .append('// Types') | |
37 .append('//') | |
38 .append() | |
39 ) | |
40 for tipe in self.__namespace.types.values(): | |
41 (c.concat(self.__generate_type(tipe)) | |
42 .append() | |
43 ) | |
44 (c.append('//') | |
45 .append('// Functions') | |
46 .append('//') | |
47 .append() | |
48 ) | |
49 for function in self.__namespace.functions.values(): | |
50 (c.concat(self.__generate_function(function)) | |
51 .append() | |
52 ) | |
53 (c.append('} // namespace %s' % self.__root_namespace) | |
54 .append('} // namespace %s' % target_namespace) | |
55 .append() | |
56 ) | |
57 # TODO(calamity): Events | |
58 return c | |
59 | |
60 def __generate_type(self, tipe): | |
Yoyo Zhou
2012/01/19 02:19:40
type_ is preferred over tipe.
calamity
2012/01/20 01:10:25
Done.
| |
61 """Generates the function definitions for a type. | |
62 """ | |
63 c = code.Code() | |
64 | |
65 (c.append('%(classname)s::%(classname)s() {}') | |
66 .append('%(classname)s::~%(classname)s() {}') | |
67 .append() | |
68 ) | |
69 c.substitute({'classname': tipe.name}) | |
70 | |
71 c.concat(self.__generate_type_populate(tipe)) | |
72 c.append() | |
73 # TODO(calamity): deal with non-serializable | |
74 c.concat(self.__generate_type_tovalue(tipe)) | |
75 c.append() | |
76 | |
77 return c | |
78 | |
79 def __generate_type_populate(self, tipe): | |
80 """Generates the function for populating a type given a pointer to it. | |
81 """ | |
82 c = code.Code() | |
83 (c.append('// static') | |
84 .sblock('bool %(name)s::Populate(const Value& value, %(name)s* out) {') | |
85 .append('if (!value.IsType(Value::TYPE_DICTIONARY))') | |
86 .append(' return false;') | |
87 .append('const DictionaryValue* dict = ' | |
88 'static_cast<const DictionaryValue*>(&value);') | |
89 .append() | |
90 ) | |
91 c.substitute({'name': tipe.name}) | |
92 | |
93 # TODO(calamity): this doesn't even handle single properties. | |
94 # add ALL the types | |
95 for prop in tipe.properties.values(): | |
96 sub = {'name': prop.name} | |
97 if prop.type == PropertyType.ARRAY: | |
98 if prop.item_type.type == PropertyType.REF: | |
99 if prop.optional: | |
100 (c.append('if (!json_schema_compiler::util::' | |
101 'GetOptionalTypes<%(type)s>(*dict,') | |
102 .append(' "%(name)s", &out->%(name)s))') | |
103 .append(' return false;') | |
104 ) | |
105 else: | |
106 (c.append('if (!json_schema_compiler::util::' | |
107 'GetTypes<%(type)s>(*dict,') | |
108 .append(' "%(name)s", &out->%(name)s))') | |
109 .append(' return false;') | |
110 ) | |
111 sub['type'] = self.__cpp_type_generator.get_type(prop.item_type, | |
112 pad_for_generics=True) | |
113 elif prop.item_type.type == PropertyType.STRING: | |
114 if prop.optional: | |
115 (c.append('if (!json_schema_compiler::util::GetOptionalStrings' | |
116 '(*dict, "%(name)s", &out->%(name)s))') | |
117 .append(' return false;') | |
118 ) | |
119 else: | |
120 (c.append('if (!json_schema_compiler::util::GetStrings' | |
121 '(*dict, "%(name)s", &out->%(name)s))') | |
122 .append(' return false;') | |
123 ) | |
124 else: | |
125 raise NotImplementedError(prop.item_type.type) | |
126 elif prop.type.is_fundamental: | |
127 c.append('if (!dict->%s)' % cpp_util.get_fundamental_value(prop, | |
128 '&out->%s' % prop.name)) | |
129 c.append(' return false;') | |
130 else: | |
131 raise NotImplementedError(prop.type) | |
132 c.substitute(sub) | |
133 (c.append('return true;') | |
134 .eblock('}') | |
135 ) | |
136 return c | |
137 | |
138 def __generate_type_tovalue(self, tipe): | |
139 """Generates a function that serializes the type into a |DictionaryValue|. | |
140 """ | |
141 c = code.Code() | |
142 (c.sblock('DictionaryValue* %s::ToValue() const {' % tipe.name) | |
143 .append('DictionaryValue* value = new DictionaryValue();') | |
144 .append() | |
145 ) | |
146 name = tipe.name.lower() | |
147 for prop in tipe.properties.values(): | |
148 prop_name = name + '_' + prop.name if name else prop.name | |
149 this_var = prop.name | |
150 c.concat(self.__create_value_from_property(prop_name, prop, this_var)) | |
151 (c.append() | |
152 .append('return value;') | |
153 .eblock('}') | |
154 ) | |
155 return c | |
156 | |
157 # TODO(calamity): object and choices proptypes | |
158 def __create_value_from_property(self, name, prop, var): | |
159 """Generates code to serialize a single property in a type. | |
160 """ | |
161 c = code.Code() | |
162 if prop.type.is_fundamental: | |
163 c.append('Value* %s_value = %s;' % | |
164 (name, cpp_util.create_fundamental_value(prop, var))) | |
165 elif prop.type == PropertyType.ARRAY: | |
166 if prop.item_type.type == PropertyType.STRING: | |
167 if prop.optional: | |
168 c.append('json_schema_compiler::util::' | |
169 'SetOptionalStrings(%s, "%s", value);' % (var, prop.name)) | |
170 else: | |
171 c.append('json_schema_compiler::util::' | |
172 'SetStrings(%s, "%s", value);' % (var, prop.name)) | |
173 else: | |
174 item_name = name + '_single' | |
175 (c.append('ListValue* %(name)s_value = new ListValue();') | |
176 .append('for (%(it_type)s::iterator it = %(var)s->begin();') | |
177 .sblock(' it != %(var)s->end(); ++it) {') | |
178 .concat(self.__create_value_from_property(item_name, prop.item_type, | |
179 '*it')) | |
180 .append('%(name)s_value->Append(%(prop_val)s_value);') | |
181 .eblock('}') | |
182 ) | |
183 c.substitute( | |
184 {'it_type': self.__cpp_type_generator.get_type(prop), | |
185 'name': name, 'var': var, 'prop_val': item_name}) | |
186 elif prop.type == PropertyType.REF: | |
187 c.append('Value* %s_value = %s.ToValue();' % (name, var)) | |
188 else: | |
Yoyo Zhou
2012/01/19 02:19:40
This also doesn't handle single properties, right?
calamity
2012/01/20 01:10:25
fundamental types and REF types are the single pro
| |
189 raise NotImplementedError | |
190 return c | |
191 | |
192 def __generate_function(self, function): | |
193 """Generates the definitions for function structs. | |
194 """ | |
195 classname = cpp_util.cpp_name(function.name) | |
196 c = code.Code() | |
197 | |
198 # Params::Populate function | |
199 if function.params: | |
200 (c.append('%(name)s::Params::Params() {}') | |
201 .append('%(name)s::Params::~Params() {}') | |
202 .append() | |
203 .concat(self.__generate_function_params_populate(function)) | |
204 .append() | |
205 ) | |
206 | |
207 # Result::Create function | |
208 c.concat(self.__generate_function_result_create(function)) | |
209 | |
210 c.substitute({'name': classname}) | |
211 | |
212 return c | |
213 | |
214 def __generate_function_params_populate(self, function): | |
215 """Generate function to populate an instance of Params given a pointer. | |
216 """ | |
217 classname = cpp_util.cpp_name(function.name) | |
218 c = code.Code() | |
219 c.append('// static') | |
220 c.append('bool %(classname)s::Params::Populate(const ListValue& args,') | |
221 c.sblock(' %(classname)s::Params* out) {') | |
222 c.substitute({'classname': classname}) | |
223 c.append('if (args.GetSize() != %d)' % len(function.params)) | |
224 c.append(' return false;') | |
225 | |
226 # TODO(calamity): generalize, needs to move to function to do populates for | |
227 # wider variety of args | |
228 for i, param in enumerate(function.params): | |
229 sub = {'name': param.name, 'pos': i} | |
230 c.append() | |
231 # TODO(calamity): Make valid for not just objects | |
232 c.append('DictionaryValue* %(name)s_param = NULL;') | |
233 c.append('if (!args.GetDictionary(%(pos)d, &%(name)s_param))') | |
234 c.append(' return false;') | |
235 if param.type == PropertyType.REF: | |
236 c.append('if (!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))') | |
237 c.append(' return false;') | |
238 sub['ctype'] = self.__cpp_type_generator.get_type(param) | |
239 elif param.type.is_fundamental: | |
240 #XXX THIS IS WRONG | |
241 c.append('// TODO Needs some sort of casting') | |
Yoyo Zhou
2012/01/19 02:19:40
Seems like you could raise NotImplementedError her
calamity
2012/01/23 05:14:45
Done.
| |
242 c.append('if (!%(name)s_param->' + | |
243 cpp_util.get_fundamental_value(param,'&out->%s' % param.name) +');') | |
244 c.append(' return false;') | |
245 elif param.type == PropertyType.OBJECT: | |
246 c.append('if (!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))') | |
247 c.append(' return false;') | |
248 sub['ctype'] = self.__cpp_type_generator.get_type(param) | |
249 elif param.type == PropertyType.CHOICES: | |
250 c.append('// TODO handle chocies') | |
251 else: | |
252 raise NotImplementedError(param.type) | |
253 c.substitute(sub) | |
254 c.append() | |
255 c.append('return true;') | |
256 c.eblock('}') | |
257 | |
258 return c | |
259 | |
260 def __generate_function_result_create(self, function): | |
261 """Generate function to create a Result given the return value. | |
262 """ | |
263 classname = cpp_util.cpp_name(function.name) | |
264 c = code.Code() | |
265 c.append('// static') | |
266 param = function.callback.param | |
267 arg = '' | |
268 if param: | |
269 if param.type == PropertyType.REF: | |
270 arg = 'const %(type)s& %(name)s' | |
271 else: | |
272 arg = 'const %(type)s %(name)s' | |
273 arg = arg % {'type': self.__cpp_type_generator.get_type(param), | |
274 'name': param.name} | |
275 c.sblock('Value* %(classname)s::Result::Create(%(arg)s) {') | |
276 sub = {'classname': classname, 'arg': arg} | |
277 # TODO(calamity): Choices | |
278 if not param: | |
279 c.append('return Value::CreateNullValue();') | |
280 else: | |
281 sub['argname'] = param.name | |
282 if param.type.is_fundamental: | |
283 c.append('return %s;' % | |
284 cpp_util.create_fundamental_value(param, param.name)) | |
285 elif param.type == PropertyType.REF: | |
286 c.append('DictionaryValue* result = new DictionaryValue();') | |
287 c.append('result->SetWithoutPathExpansion("%(argname)s",' | |
288 '%(argname)s.ToValue());') | |
289 c.append('return result;') | |
290 elif param.type == PropertyType.OBJECT: | |
291 c.append('// TODO object stuff') | |
292 elif param.type == PropertyType.ARRAY: | |
293 c.append('// TODO array stuff') | |
294 else: | |
295 raise NotImplementedError(param.type) | |
296 c.substitute(sub) | |
297 c.eblock('}') | |
298 return c | |
OLD | NEW |