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

Side by Side Diff: tools/json_schema_compiler/generate_cc.py

Issue 9114036: Code generation for extensions api (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: some rework Created 8 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698