OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2011 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 type_manager | |
8 | |
9 class CC_Generator(object): | |
not at google - send to devlin
2012/01/13 02:14:09
I like this name, so the file should be called cc_
calamity
2012/01/16 04:01:06
Done.
| |
10 """A .cc generator for a namespace.""" | |
11 | |
12 def __init__(self, namespace, model): | |
13 self.type_manager = type_manager.TypeManager(namespace, model) | |
14 self.namespace = namespace | |
15 | |
16 def generate(self): | |
17 """Generates the .cc code for a single namespace. | |
not at google - send to devlin
2012/01/13 02:14:09
"""Generates a code.Code object with the .cc code
calamity
2012/01/16 04:01:06
Done.
| |
18 | |
19 Returns a code.Code object. | |
20 """ | |
21 include_path = self.namespace.parent_dir | |
22 filename = self.namespace.filename | |
23 c = code.Code() | |
24 (c.append(code.CHROMIUM_LICENSE).append() | |
not at google - send to devlin
2012/01/13 02:14:09
put the second .append() on its own line; this wou
calamity
2012/01/16 04:01:06
Done.
| |
25 .append(code.WARNING_MESSAGE % self.namespace.parent_path) | |
26 .append() | |
27 .append('#include "tools/json_schema_compiler/util.h"') | |
28 .append('#include "%s/%s.h"' % (include_path, filename)) | |
29 # .append('#include "base/json/json_converter.h"') | |
not at google - send to devlin
2012/01/13 02:14:09
delete
calamity
2012/01/16 04:01:06
Done.
| |
30 .append() | |
31 .append('namespace extensions {') | |
not at google - send to devlin
2012/01/13 02:14:09
"extensions" needs to be taken from the command-li
calamity
2012/01/16 04:01:06
Done.
| |
32 .append('namespace %s {' % filename) | |
33 .append() | |
34 .append('//') | |
35 .append('// Types') | |
36 .append('//') | |
37 .append() | |
38 ) | |
39 for tipe in self.namespace.types.values(): | |
40 c.add(self.generate_type(tipe)) | |
not at google - send to devlin
2012/01/13 02:14:09
pull the last "c.append()" out of generate_type an
calamity
2012/01/16 04:01:06
Done. Also did the same with all other "c.append()
| |
41 c.append('//') | |
42 c.append('// Functions') | |
43 c.append('//') | |
44 c.append() | |
45 for function in self.namespace.functions.values(): | |
46 c.add(self.generate_function(function)) | |
47 c.append('} // namespace extensions') | |
not at google - send to devlin
2012/01/13 02:14:09
ditto extensions
calamity
2012/01/16 04:01:06
Done.
| |
48 c.append('} // namespace %s' % filename) | |
49 # TODO(calamity): Events | |
50 return c | |
51 | |
52 def generate_type(self, tipe): | |
53 """Generates the function definitions for a type in the namespace.""" | |
not at google - send to devlin
2012/01/13 02:14:09
... for a type.
"""
(no need for "in the namespac
calamity
2012/01/16 04:01:06
Done.
| |
54 c = code.Code() | |
55 classname = '%s' % (tipe.name) | |
not at google - send to devlin
2012/01/13 02:14:09
can delete this line and inline it?
...
c.substit
calamity
2012/01/16 04:01:06
Done.
| |
56 | |
57 c.append('%(classname)s::%(classname)s() {}') | |
58 c.append('%(classname)s::~%(classname)s() {}') | |
59 c.substitute({'classname': classname}) | |
60 c.append() | |
61 | |
62 c.add(self.generate_type_populate(tipe)) | |
63 # TODO(calamity): deal with non-serializable | |
64 c.add(self.generate_type_tovalue(tipe)) | |
65 c.append() | |
66 | |
67 return c | |
68 | |
69 def generate_type_populate(self, tipe): | |
70 """Generates the function for populating a type given a pointer to it.""" | |
71 c = code.Code() | |
72 c.append('// static') | |
73 c.sblock('bool %(name)s::Populate(const Value& value, %(name)s* out) {') | |
74 c.substitute({'name': tipe.name}) | |
75 c.append('if (!value.IsType(Value::TYPE_DICTIONARY))') | |
76 c.append(' return false;') | |
77 c.append('const DictionaryValue* dict = ' | |
78 'static_cast<const DictionaryValue*>(&value);') | |
79 | |
80 c.append() | |
81 # TODO(calamity): this doesn't even handle single properties. | |
82 # add ALL the types | |
83 for prop in tipe.properties.values(): | |
84 sub = {'name': prop.name} | |
85 if prop.type == PropertyType.ARRAY: | |
86 if prop.item_type.type == PropertyType.REF: | |
87 if prop.optional: | |
88 c.append('if (!json_schema_compiler::util::GetOptionalTypes<%(type)s >(*dict,') | |
not at google - send to devlin
2012/01/13 02:14:09
this line is too long.
this makes me think though
calamity
2012/01/16 04:01:06
Yeah, but as always it's a tradeoff between usabil
not at google - send to devlin
2012/01/17 01:59:24
Not really, it's not global state because it's not
| |
89 c.append(' "%(name)s", &out->%(name)s))') | |
90 c.append(' return false;') | |
91 else: | |
92 c.append('if (!json_schema_compiler::util::GetTypes<%(type)s>(*dict, ') | |
93 c.append(' "%(name)s", &out->%(name)s))') | |
94 c.append(' return false;') | |
95 sub['type'] = self.type_manager.get_generic_type(prop.item_type) | |
96 elif prop.item_type.json_type == 'string': | |
97 if prop.optional: | |
98 c.append('if (!json_schema_compiler::util::GetOptionalStrings' | |
99 '(*dict, "%(name)s", &out->%(name)s))') | |
100 c.append(' return false;') | |
101 else: | |
102 c.append('if (!json_schema_compiler::util::GetStrings' | |
103 '(*dict, "%(name)s", &out->%(name)s))') | |
104 c.append(' return false;') | |
calamity
2012/01/16 04:01:06
Clearly this if block is going to grow. On a dev b
not at google - send to devlin
2012/01/17 01:59:24
I'm missing the context for this comment.
| |
105 else: | |
106 raise NotImplementedError(prop.item_type.json_type) | |
107 elif prop.type == PropertyType.FUNDAMENTAL: | |
108 c.append('if(!dict->%s)' % get_fundamental_value(prop, | |
109 '&out->%s' % prop.name)) | |
110 c.append(' return false;') | |
111 else: | |
112 raise NotImplementedError(prop.type) | |
113 c.substitute(sub) | |
114 c.append('return true;') | |
115 c.eblock('}') | |
116 c.append() | |
117 return c | |
118 | |
119 def generate_type_tovalue(self, tipe): | |
120 """Generates a function that serializes the type into a | |
121 |DictionaryValue|.""" | |
122 c = code.Code() | |
123 c.sblock('DictionaryValue* %s::ToValue() const {' % tipe.name) | |
124 name = tipe.name.lower() | |
125 c.append('DictionaryValue* value = new DictionaryValue();') | |
126 c.append() | |
127 for prop in tipe.properties.values(): | |
128 prop_name = name + '_' + prop.name if name else prop.name | |
129 this_var = prop.name | |
130 c.add(self.create_value_from_property(prop_name, prop, this_var)) | |
131 c.append() | |
132 c.append('return value;') | |
133 | |
134 c.eblock('}') | |
135 return c | |
136 | |
137 # TODO(calamity): object and choices proptypes | |
138 def create_value_from_property(self, name, prop, var): | |
139 """Generates code to serialize a single property in a type.""" | |
140 c = code.Code() | |
141 if prop.type == PropertyType.FUNDAMENTAL: | |
142 c.append( | |
143 'Value* %s_value = %s;' % (name, create_fundamental_value(prop, var))) | |
144 elif prop.type == PropertyType.ARRAY: | |
145 if prop.item_type.json_type == 'string': | |
146 if prop.optional: | |
147 c.append('json_schema_compiler::util::SetOptionalStrings(%s, "%s", val ue);' | |
148 % (var, prop.name)) | |
149 else: | |
150 c.append('json_schema_compiler::util::SetStrings(%s, "%s", value);' % | |
151 (var, prop.name)) | |
152 else: | |
153 item_name = name + '_single' | |
154 c.append('ListValue* %(name)s_value = new ListValue();') | |
155 c.append('for (%(it_type)s::iterator it = %(var)s->begin();') | |
156 c.sblock(' it != %(var)s->end(); ++it) {') | |
157 c.add(self.create_value_from_property(item_name, prop.item_type, '*it')) | |
158 c.append('%(name)s_value->Append(%(prop_val)s_value);') | |
159 c.substitute( | |
160 {'it_type': self.type_manager.get_type(prop), | |
161 'name': name, 'var': var, 'prop_val': item_name}) | |
162 c.eblock('}') | |
163 elif prop.type == PropertyType.REF: | |
164 c.append('Value* %s_value = %s.ToValue();' % (name, var)) | |
165 else: | |
166 raise NotImplementedError | |
167 return c | |
168 | |
169 def generate_function(self, function): | |
170 """Generates the definitions for function structs.""" | |
171 classname = code.cpp_name(function.name) | |
172 c = code.Code() | |
173 | |
174 # Params::Populate function | |
175 if function.params: | |
176 c.append('%(name)s::Params::Params() {}') | |
177 c.append('%(name)s::Params::~Params() {}') | |
178 c.append() | |
179 c.add(self.generate_function_params_populate(function)) | |
180 | |
181 # Result::Create function | |
182 c.add(self.generate_function_result_create(function)) | |
183 | |
184 c.substitute({'name': classname}) | |
185 | |
186 return c | |
187 | |
188 def generate_function_params_populate(self, function): | |
189 """Generate function to populate an instance of Params given a pointer.""" | |
190 classname = code.cpp_name(function.name) | |
191 c = code.Code() | |
192 c.append('// static') | |
193 c.append('bool %(classname)s::Params::Populate(const ListValue& args,') | |
194 c.sblock(' %(classname)s::Params* out) {') | |
195 c.substitute({'classname': classname}) | |
196 c.append('if (args.GetSize() != %d)' % len(function.params)) | |
197 c.append(' return false;') | |
198 | |
199 # TODO(calamity): generalize, needs to move to function to do populates for | |
200 # wider variety of args | |
201 for i, param in enumerate(function.params): | |
202 sub = {'name': param.name, 'pos': i} | |
203 c.append() | |
204 # TODO(calamity): Make valid for not just objects | |
205 c.append('DictionaryValue* %(name)s_param = NULL;') | |
206 c.append('if (!args.GetDictionary(%(pos)d, &%(name)s_param))') | |
207 c.append(' return false;') | |
208 if param.type == PropertyType.REF: | |
209 c.append('if (!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))') | |
210 c.append(' return false;') | |
211 sub['ctype'] = self.type_manager.get_type(param) | |
212 elif param.type == PropertyType.FUNDAMENTAL: | |
213 #XXX THIS IS WRONG | |
214 c.append('// TODO Needs some sort of casting') | |
215 c.append('if (!%(name)s_param->' + | |
216 get_fundamental_value(param,'&out->%s' % param.name) +');') | |
217 c.append(' return false;') | |
218 elif param.type == PropertyType.OBJECT: | |
219 c.append('if(!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))') | |
220 c.append(' return false;') | |
221 sub['ctype'] = self.type_manager.get_type(param) | |
222 elif param.type == PropertyType.CHOICES: | |
223 c.append('// TODO handle chocies') | |
224 else: | |
225 raise NotImplementedError(param.type) | |
226 c.substitute(sub) | |
227 c.append() | |
228 c.append('return true;') | |
229 c.eblock('}') | |
230 c.append() | |
231 | |
232 return c | |
233 | |
234 def generate_function_result_create(self, function): | |
235 """Generate function to create a Result given the return value.""" | |
236 classname = code.cpp_name(function.name) | |
237 c = code.Code() | |
238 c.append('// static') | |
239 param = function.callback.param | |
240 arg = '' | |
241 if param: | |
242 arg = 'const ' + self.type_manager.parameter_declaration(param, | |
243 type_modifiers={PropertyType.REF: type_manager.ParamFormat.REFERENCE}) | |
244 c.sblock('Value* %(classname)s::Result::Create(%(arg)s) {') | |
245 sub = {'classname': classname, 'arg': arg} | |
246 # TODO(calamity): Choices | |
247 if not param: | |
248 c.append('return Value::CreateNullValue();') | |
249 else: | |
250 sub['argname'] = param.name | |
251 if param.type == PropertyType.FUNDAMENTAL: | |
252 c.append('return %s;' % create_fundamental_value(param, param.name)) | |
253 elif param.type == PropertyType.REF: | |
254 c.append('DictionaryValue* result = new DictionaryValue();') | |
255 c.append('result->Set("%(argname)s", %(argname)s.ToValue());') | |
not at google - send to devlin
2012/01/13 02:14:09
SetWithoutPathExpansion
(need to audit this whole
calamity
2012/01/16 04:01:06
Done.
| |
256 c.append('return result;') | |
257 elif param.type == PropertyType.OBJECT: | |
258 c.append('// TODO object stuff') | |
259 elif param.type == PropertyType.ARRAY: | |
260 c.append('// TODO array stuff') | |
261 else: | |
262 raise NotImplementedError(param.type) | |
263 c.substitute(sub) | |
264 c.eblock('}') | |
265 c.append() | |
266 return c | |
267 | |
268 def create_fundamental_value(prop, var): | |
269 """Returns the C++ code for creating a value of the given property type | |
270 using the given variable.""" | |
271 return { | |
272 'string': 'Value::CreateStringValue(%s)', | |
273 'boolean': 'Value::CreateBooleanValue(%s)', | |
274 'integer': 'Value::CreateIntegerValue(%s)', | |
275 'double': 'Value::CreateDoubleValue(%s)', | |
276 }[prop.json_type] % var | |
277 | |
278 | |
279 def get_fundamental_value(prop, var): | |
280 """Returns the C++ code for retrieving a fundamental type from a Value | |
281 into a variable.""" | |
282 return { | |
283 'string': 'GetAsString(%s)', | |
284 'boolean': 'GetAsBoolean(%s)', | |
285 'integer': 'GetAsInteger(%s)', | |
286 'double': 'GetAsDouble(%s)', | |
287 }[prop.json_type] % var | |
OLD | NEW |