Chromium Code Reviews| 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 |