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