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

Unified Diff: tools/json_schema_compiler/cc_generator.py

Issue 9114036: Code generation for extensions api (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: switched namespaces, various 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 side-by-side diff with in-line comments
Download patch
Index: tools/json_schema_compiler/cc_generator.py
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..45277813ec01431f7d994146da4b578a12038ff9
--- /dev/null
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -0,0 +1,294 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from model import PropertyType
+import code
+import cpp_type_generator
Yoyo Zhou 2012/01/23 23:16:42 Looks like you're not using this import. (Same in
calamity 2012/01/24 22:57:22 Done.
+import cpp_util
+
+class CCGenerator(object):
+ """A .cc generator for a namespace.
+ """
+ def __init__(self, namespace, model, cpp_type_generator):
+ self._cpp_type_generator = cpp_type_generator
+ self._namespace = namespace
+ self._target_namespace = (
+ self._cpp_type_generator.getCppNamespaceName(self._namespace))
+
+ def generate(self):
Yoyo Zhou 2012/01/23 23:16:42 Method names should start with caps.
calamity 2012/01/24 22:57:22 Done.
+ """Generates a code.Code object with the .cc for a single namespace.
+ """
+ c = code.Code()
+ (c.append(cpp_util.CHROMIUM_LICENSE)
+ .append()
+ .append(cpp_util.GENERATED_FILE_MESSAGE % self._namespace.source_file)
+ .append()
+ .append('#include "tools/json_schema_compiler/util.h"')
+ .append('#include "%s/%s.h"' %
+ (self._namespace.source_file_dir, self._target_namespace))
+ .append()
+ .concat(self._cpp_type_generator.getCppNamespaceStart())
+ .append()
+ .append('//')
+ .append('// Types')
+ .append('//')
+ .append()
+ )
+ for type_ in self._namespace.types.values():
+ (c.concat(self._generateType(type_))
+ .append()
+ )
+ (c.append('//')
+ .append('// Functions')
+ .append('//')
+ .append()
+ )
+ for function in self._namespace.functions.values():
+ (c.concat(self._generateFunction(function))
+ .append()
+ )
+ (c.concat(self._cpp_type_generator.getCppNamespaceEnd())
+ .append()
+ )
+ # TODO(calamity): Events
+ return c
+
+ def _generateType(self, type_):
+ """Generates the function definitions for a type.
+ """
+ c = code.Code()
+
+ (c.append('%(classname)s::%(classname)s() {}')
+ .append('%(classname)s::~%(classname)s() {}')
+ .append()
+ )
+ c.substitute({'classname': type_.name})
+
+ c.concat(self._generateTypePopulate(type_))
+ c.append()
+ # TODO(calamity): deal with non-serializable
+ c.concat(self._generateTypeTovalue(type_))
+ c.append()
+
+ return c
+
+ def _generateTypePopulate(self, type_):
+ """Generates the function for populating a type given a pointer to it.
+ """
+ c = code.Code()
+ (c.append('// static')
+ .sblock('bool %(name)s::Populate(const Value& value, %(name)s* out) {')
+ .append('if (!value.IsType(Value::TYPE_DICTIONARY))')
+ .append(' return false;')
+ .append('const DictionaryValue* dict = '
+ 'static_cast<const DictionaryValue*>(&value);')
+ .append()
+ )
+ c.substitute({'name': type_.name})
+
+ # TODO(calamity): this handle single PropertyType.REF properties.
Yoyo Zhou 2012/01/23 23:16:42 This comment seems incomplete.
calamity 2012/01/24 22:57:22 Done.
+ # add ALL the types
+ for prop in type_.properties.values():
+ sub = {'name': prop.name}
+ if prop.type_ == PropertyType.ARRAY:
+ if prop.item_type.type_ == PropertyType.REF:
+ if prop.optional:
+ (c.append('if (!json_schema_compiler::util::'
+ 'GetOptionalTypes<%(type)s>(*dict,')
+ .append(' "%(name)s", &out->%(name)s))')
+ .append(' return false;')
+ )
+ else:
+ (c.append('if (!json_schema_compiler::util::'
+ 'GetTypes<%(type)s>(*dict,')
+ .append(' "%(name)s", &out->%(name)s))')
+ .append(' return false;')
+ )
+ sub['type'] = self._cpp_type_generator.getType(prop.item_type,
+ pad_for_generics=True)
+ elif prop.item_type.type_ == PropertyType.STRING:
+ if prop.optional:
+ (c.append('if (!json_schema_compiler::util::GetOptionalStrings'
+ '(*dict, "%(name)s", &out->%(name)s))')
+ .append(' return false;')
+ )
+ else:
+ (c.append('if (!json_schema_compiler::util::GetStrings'
+ '(*dict, "%(name)s", &out->%(name)s))')
+ .append(' return false;')
+ )
+ else:
+ raise NotImplementedError(prop.item_type.type_)
+ elif proptype_.is_fundamental:
Yoyo Zhou 2012/01/23 23:16:42 prop.type_?
calamity 2012/01/24 22:57:22 Done.
+ c.append('if (!dict->%s)' %
+ cpp_util.getFundamentalValue(prop, '&out->%s' % prop.name))
+ c.append(' return false;')
+ else:
+ raise NotImplementedError(prop.type_)
+ c.substitute(sub)
+ (c.append('return true;')
+ .eblock('}')
+ )
+ return c
+
+ def _generateTypeTovalue(self, type_):
Yoyo Zhou 2012/01/23 23:16:42 ToValue
calamity 2012/01/24 22:57:22 Done.
+ """Generates a function that serializes the type into a |DictionaryValue|.
+ """
+ c = code.Code()
+ (c.sblock('DictionaryValue* %s::ToValue() const {' % type_.name)
+ .append('DictionaryValue* value = new DictionaryValue();')
+ .append()
+ )
+ name = type_.name.lower()
+ for prop in type_.properties.values():
+ prop_name = name + '_' + prop.name if name else prop.name
+ this_var = prop.name
+ c.concat(self._createValueFromProperty(prop_name, prop, this_var))
+ (c.append()
+ .append('return value;')
+ .eblock('}')
+ )
+ return c
+
+ # TODO(calamity): object and choices proptypes
+ def _createValueFromProperty(self, name, prop, var):
+ """Generates code to serialize a single property in a type.
+ """
+ c = code.Code()
+ if prop.type_.is_fundamental:
+ c.append('Value* %s_value = %s;' %
+ (name, cpp_util.createFundamentalValue(prop, var)))
+ elif prop.type_ == PropertyType.ARRAY:
+ if prop.item_type.type_ == PropertyType.STRING:
+ if prop.optional:
+ c.append('json_schema_compiler::util::'
+ 'SetOptionalStrings(%s, "%s", value);' % (var, prop.name))
+ else:
+ c.append('json_schema_compiler::util::'
+ 'SetStrings(%s, "%s", value);' % (var, prop.name))
+ else:
+ item_name = name + '_single'
+ (c.append('ListValue* %(name)s_value = new ListValue();')
+ .append('for (%(it_type)s::iterator it = %(var)s->begin();')
+ .sblock(' it != %(var)s->end(); ++it) {')
+ .concat(self._createValueFromProperty(item_name, prop.item_type,
+ '*it'))
+ .append('%(name)s_value->Append(%(prop_val)s_value);')
+ .eblock('}')
+ )
+ c.substitute(
+ {'it_type': self._cpp_type_generator.getType(prop),
+ 'name': name, 'var': var, 'prop_val': item_name})
+ elif prop.type_ == PropertyType.REF:
+ c.append('Value* %s_value = %s.ToValue();' % (name, var))
+ else:
+ raise NotImplementedError
+ return c
+
+ def _generateFunction(self, function):
+ """Generates the definitions for function structs.
+ """
+ classname = cpp_util.cppName(function.name)
+ c = code.Code()
+
+ # Params::Populate function
+ if function.params:
+ (c.append('%(name)s::Params::Params() {}')
+ .append('%(name)s::Params::~Params() {}')
+ .append()
+ .concat(self._generateFunctionParamsCreate(function))
+ .append()
+ )
+
+ # Result::Create function
+ c.concat(self._generateFunctionResultCreate(function))
+
+ c.substitute({'name': classname})
+
+ return c
+
+ def _generateFunctionParamsCreate(self, function):
+ """Generate function to create an instance of Params given a pointer.
+ """
+ classname = cpp_util.cppName(function.name)
+ c = code.Code()
+ c.append('// static')
+ c.append('%(classname)s::Params* %(classname)s::Params::Create'
+ '(const ListValue& args) {')
+ c.substitute({'classname': classname})
+ c.append('if (args.GetSize() != %d)' % len(function.params))
+ c.append(' return NULL;')
+
+ # TODO(calamity): generalize, needs to move to function to do populates for
+ # wider variety of args
+ for i, param in enumerate(function.params):
+ sub = {'name': param.name, 'pos': i}
+ c.append()
+ # TODO(calamity): Make valid for not just objects
+ c.append('DictionaryValue* %(name)s_param = NULL;')
+ c.append('if (!args.GetDictionary(%(pos)d, &%(name)s_param))')
+ c.append(' return NULL;')
+ c.append('scoped_ptr<Params> out;')
Yoyo Zhou 2012/01/23 23:16:42 Should this be outside the for loop? Why not use
calamity 2012/01/24 22:57:22 Done. I made it a scoped_ptr so it would clean up
+ if param.type_ == PropertyType.REF:
+ c.append('if (!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))')
+ c.append(' return NULL;')
+ sub['ctype'] = self._cpp_type_generator.getType(param)
+ elif param.type_.is_fundamental:
+ raise NotImplementedError('Fundamental types are unimplemented')
+ elif param.type_ == PropertyType.OBJECT:
+ c.append('if (!%(ctype)s::Populate(*%(name)s_param, &out->%(name)s))')
+ c.append(' return NULL;')
+ sub['ctype'] = self._cpp_type_generator.getType(param)
+ elif param.type_ == PropertyType.CHOICES:
+ raise NotImplementedError('Choices is unimplemented')
+ else:
+ raise NotImplementedError(param.type_)
+ c.substitute(sub)
+ c.append()
+ c.append('return out.release();')
+ c.eblock('}')
+
+ return c
+
+ def _generateFunctionResultCreate(self, function):
+ """Generate function to create a Result given the return value.
+ """
+ classname = cpp_util.cppName(function.name)
+ c = code.Code()
+ c.append('// static')
+ param = function.callback.param
+ arg = ''
+ if param:
+ if param.type_ == PropertyType.REF:
+ arg = 'const %(type)s& %(name)s'
+ else:
+ arg = 'const %(type)s %(name)s'
+ arg = arg % {
+ 'type': self._cpp_type_generator.getType(param),
+ 'name': param.name
+ }
+ c.sblock('Value* %(classname)s::Result::Create(%(arg)s) {')
+ sub = {'classname': classname, 'arg': arg}
+ # TODO(calamity): Choices
+ if not param:
+ c.append('return Value::CreateNullValue();')
+ else:
+ sub['argname'] = param.name
+ if param.type_.is_fundamental:
+ c.append('return %s;' %
+ cpp_util.createFundamentalValue(param, param.name))
+ elif param.type_ == PropertyType.REF:
+ c.append('DictionaryValue* result = new DictionaryValue();')
+ c.append('result->SetWithoutPathExpansion("%(argname)s",'
+ '%(argname)s.ToValue());')
+ c.append('return result;')
+ elif param.type_ == PropertyType.OBJECT:
+ raise NotImplementedError('Objects not implemented')
+ elif param.type_ == PropertyType.ARRAY:
+ raise NotImplementedError('Arrays not implemented')
+ else:
+ raise NotImplementedError(param.type_)
+ c.substitute(sub)
+ c.eblock('}')
+ return c

Powered by Google App Engine
This is Rietveld 408576698