| 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
|
| index bbda061682dafb624308865cf1bb171dc7521853..ce65ed2165634d8bbb9bb4efc4db0f63b3e72e60 100644
|
| --- a/tools/json_schema_compiler/cc_generator.py
|
| +++ b/tools/json_schema_compiler/cc_generator.py
|
| @@ -3,8 +3,10 @@
|
| # found in the LICENSE file.
|
|
|
| from model import PropertyType
|
| +import any_helper
|
| import code
|
| import cpp_util
|
| +import model
|
| import util_cc_helper
|
|
|
| class CCGenerator(object):
|
| @@ -17,6 +19,7 @@ class CCGenerator(object):
|
| self._cpp_type_generator.GetCppNamespaceName(self._namespace))
|
| self._util_cc_helper = (
|
| util_cc_helper.UtilCCHelper(self._cpp_type_generator))
|
| + self._any_helper = any_helper.AnyHelper()
|
|
|
| def Generate(self):
|
| """Generates a code.Code object with the .cc for a single namespace.
|
| @@ -40,6 +43,7 @@ class CCGenerator(object):
|
| .Append('using base::Value;')
|
| .Append('using base::DictionaryValue;')
|
| .Append('using base::ListValue;')
|
| + .Append('using %s;' % any_helper.ANY_CLASS)
|
| .Append()
|
| .Concat(self._cpp_type_generator.GetRootNamespaceStart())
|
| .Concat(self._cpp_type_generator.GetNamespaceStart())
|
| @@ -62,7 +66,8 @@ class CCGenerator(object):
|
| .Append()
|
| )
|
| for function in self._namespace.functions.values():
|
| - (c.Concat(self._GenerateFunction(function))
|
| + (c.Concat(self._GenerateFunction(
|
| + cpp_util.Classname(function.name), function))
|
| .Append()
|
| )
|
| (c.Concat(self._cpp_type_generator.GetNamespaceEnd())
|
| @@ -78,25 +83,43 @@ class CCGenerator(object):
|
| classname = cpp_util.Classname(type_.name)
|
| c = code.Code()
|
|
|
| - (c.Concat(self._GeneratePropertyFunctions(
|
| - cpp_namespace, type_.properties.values()))
|
| - .Append('%(namespace)s::%(classname)s() {}')
|
| - .Append('%(namespace)s::~%(classname)s() {}')
|
| - .Append()
|
| - )
|
| - if type_.from_json:
|
| - (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_))
|
| + if type_.functions:
|
| + # Types with functions are not instantiable in C++ because they are
|
| + # handled in pure Javascript and hence have no properties or
|
| + # additionalProperties.
|
| + if type_.properties:
|
| + raise NotImplementedError('\n'.join(model.GetModelHierarchy(type_)) +
|
| + '\nCannot generate both functions and properties on a type')
|
| + for function in type_.functions.values():
|
| + (c.Concat(
|
| + self._GenerateFunction(
|
| + cpp_namespace + '::' + cpp_util.Classname(function.name),
|
| + function))
|
| + .Append()
|
| + )
|
| + else:
|
| + (c.Concat(self._GeneratePropertyFunctions(
|
| + cpp_namespace, type_.properties.values()))
|
| + .Append('%(namespace)s::%(classname)s() {}')
|
| + .Append('%(namespace)s::~%(classname)s() {}')
|
| .Append()
|
| )
|
| - if type_.from_client:
|
| - c.Concat(self._GenerateTypeToValue(cpp_namespace, type_))
|
| - c.Append()
|
| + if type_.from_json:
|
| + (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_))
|
| + .Append()
|
| + )
|
| + if type_.from_client:
|
| + (c.Concat(self._GenerateTypeToValue(cpp_namespace, type_))
|
| + .Append()
|
| + )
|
| c.Substitute({'classname': classname, 'namespace': cpp_namespace})
|
|
|
| return c
|
|
|
| def _GenerateTypePopulate(self, cpp_namespace, type_):
|
| """Generates the function for populating a type given a pointer to it.
|
| +
|
| + E.g for type "Foo", generates Foo::Populate()
|
| """
|
| classname = cpp_util.Classname(type_.name)
|
| c = code.Code()
|
| @@ -112,7 +135,16 @@ class CCGenerator(object):
|
| for prop in type_.properties.values():
|
| c.Concat(self._InitializePropertyToDefault(prop, 'out'))
|
| for prop in type_.properties.values():
|
| - c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
|
| + if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
|
| + c.Append('out->additional_properties.MergeDictionary(dict);')
|
| + # remove all keys that are actual properties
|
| + for cur_prop in type_.properties.values():
|
| + if prop != cur_prop:
|
| + c.Append('out->additional_properties'
|
| + '.RemoveWithoutPathExpansion("%s", NULL);' % cur_prop.name)
|
| + c.Append()
|
| + else:
|
| + c.Concat(self._GenerateTypePopulateProperty(prop, 'dict', 'out'))
|
| (c.Append('return true;')
|
| .Eblock('}')
|
| )
|
| @@ -149,6 +181,8 @@ class CCGenerator(object):
|
|
|
| def _GenerateTypeToValue(self, cpp_namespace, type_):
|
| """Generates a function that serializes the type into a |DictionaryValue|.
|
| +
|
| + E.g. for type "Foo" generates Foo::ToValue()
|
| """
|
| c = code.Code()
|
| (c.Sblock('scoped_ptr<DictionaryValue> %s::ToValue() const {' %
|
| @@ -157,51 +191,54 @@ class CCGenerator(object):
|
| .Append()
|
| )
|
| for prop in type_.properties.values():
|
| - if prop.optional:
|
| - if prop.type_ == PropertyType.ENUM:
|
| - c.Sblock('if (%s != %s)' %
|
| - (prop.unix_name, self._cpp_type_generator.GetEnumNoneValue(prop)))
|
| - else:
|
| - c.Sblock('if (%s.get())' % prop.unix_name)
|
| - c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
|
| - prop.name,
|
| - self._CreateValueFromProperty(prop, prop.unix_name)))
|
| - if prop.optional:
|
| - c.Eblock();
|
| + if prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
|
| + c.Append('value->MergeDictionary(&%s);' % prop.unix_name)
|
| + else:
|
| + if prop.optional:
|
| + if prop.type_ == PropertyType.ENUM:
|
| + c.Sblock('if (%s != %s)' %
|
| + (prop.unix_name,
|
| + self._cpp_type_generator.GetEnumNoneValue(prop)))
|
| + else:
|
| + c.Sblock('if (%s.get())' % prop.unix_name)
|
| + c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
|
| + prop.name,
|
| + self._CreateValueFromProperty(prop, prop.unix_name)))
|
| + if prop.optional:
|
| + c.Eblock();
|
| (c.Append()
|
| .Append('return value.Pass();')
|
| .Eblock('}')
|
| )
|
| return c
|
|
|
| - def _GenerateFunction(self, function):
|
| + def _GenerateFunction(self, cpp_namespace, function):
|
| """Generates the definitions for function structs.
|
| """
|
| - classname = cpp_util.Classname(function.name)
|
| c = code.Code()
|
|
|
| # Params::Populate function
|
| if function.params:
|
| - c.Concat(self._GeneratePropertyFunctions(classname + '::Params',
|
| + c.Concat(self._GeneratePropertyFunctions(cpp_namespace + '::Params',
|
| function.params))
|
| - (c.Append('%(name)s::Params::Params() {}')
|
| - .Append('%(name)s::Params::~Params() {}')
|
| + (c.Append('%(cpp_namespace)s::Params::Params() {}')
|
| + .Append('%(cpp_namespace)s::Params::~Params() {}')
|
| .Append()
|
| - .Concat(self._GenerateFunctionParamsCreate(function))
|
| + .Concat(self._GenerateFunctionParamsCreate(cpp_namespace, function))
|
| .Append()
|
| )
|
|
|
| # Result::Create function
|
| if function.callback:
|
| - c.Concat(self._GenerateFunctionResultCreate(function))
|
| + c.Concat(self._GenerateFunctionResultCreate(cpp_namespace, function))
|
|
|
| - c.Substitute({'name': classname})
|
| + c.Substitute({'cpp_namespace': cpp_namespace})
|
|
|
| return c
|
|
|
| def _GenerateCreateEnumValue(self, cpp_namespace, prop):
|
| - """Generates a function that returns the |StringValue| representation of an
|
| - enum.
|
| + """Generates CreateEnumValue() that returns the |StringValue|
|
| + representation of an enum.
|
| """
|
| c = code.Code()
|
| c.Append('// static')
|
| @@ -233,15 +270,18 @@ class CCGenerator(object):
|
| return c
|
|
|
| def _CreateValueFromProperty(self, prop, var):
|
| - """Creates a Value given a single property. Generated code passes ownership
|
| + """Creates a Value given a property. Generated code passes ownership
|
| to caller.
|
|
|
| var: variable or variable*
|
| +
|
| + E.g for std::string, generate Value::CreateStringValue(var)
|
| """
|
| if prop.type_ == PropertyType.CHOICES:
|
| - # CHOICES conversion not implemented because it's not used. If needed,
|
| - # write something to generate a function that returns a scoped_ptr<Value>
|
| - # and put it in _GeneratePropertyFunctions.
|
| + # CHOICES conversion not implemented. If needed, write something to
|
| + # generate a function that returns a scoped_ptr<Value> and put it in
|
| + # _GeneratePropertyFunctions, then use it here. Look at CreateEnumValue()
|
| + # for reference.
|
| raise NotImplementedError(
|
| 'Conversion of CHOICES to Value not implemented')
|
| if prop.type_ in (PropertyType.REF, PropertyType.OBJECT):
|
| @@ -249,6 +289,10 @@ class CCGenerator(object):
|
| return '%s->ToValue().release()' % var
|
| else:
|
| return '%s.ToValue().release()' % var
|
| + elif prop.type_ == PropertyType.ANY:
|
| + return '%s.DeepCopy()' % self._any_helper.GetValue(prop, var)
|
| + elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES:
|
| + return '%s.DeepCopy()' % var
|
| elif prop.type_ == PropertyType.ENUM:
|
| return 'CreateEnumValue(%s).release()' % var
|
| elif prop.type_ == PropertyType.ARRAY:
|
| @@ -291,19 +335,20 @@ class CCGenerator(object):
|
| })
|
| return c
|
|
|
| - def _GenerateFunctionParamsCreate(self, function):
|
| + def _GenerateFunctionParamsCreate(self, cpp_namespace, function):
|
| """Generate function to create an instance of Params. The generated
|
| function takes a ListValue of arguments.
|
| +
|
| + E.g for function "Bar", generate Bar::Params::Create()
|
| """
|
| - classname = cpp_util.Classname(function.name)
|
| c = code.Code()
|
| (c.Append('// static')
|
| - .Sblock('scoped_ptr<%(classname)s::Params> %(classname)s::Params::Create'
|
| - '(const ListValue& args) {')
|
| + .Sblock('scoped_ptr<%(cpp_namespace)s::Params> '
|
| + '%(cpp_namespace)s::Params::Create(const ListValue& args) {')
|
| .Concat(self._GenerateParamsCheck(function, 'args'))
|
| .Append('scoped_ptr<Params> params(new Params());')
|
| )
|
| - c.Substitute({'classname': classname})
|
| + c.Substitute({'cpp_namespace': cpp_namespace})
|
|
|
| for param in function.params:
|
| c.Concat(self._InitializePropertyToDefault(param, 'params'))
|
| @@ -353,7 +398,8 @@ class CCGenerator(object):
|
| c = code.Code()
|
| c.Sblock('{')
|
|
|
| - if check_type and prop.type_ != PropertyType.CHOICES:
|
| + if check_type and prop.type_ not in (
|
| + PropertyType.CHOICES, PropertyType.ANY):
|
| (c.Append('if (!%(value_var)s->IsType(%(value_type)s))')
|
| .Append(' return %(failure_value)s;')
|
| )
|
| @@ -389,6 +435,10 @@ class CCGenerator(object):
|
| 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))')
|
| .Append(' return %(failure_value)s;')
|
| )
|
| + elif prop.type_ == PropertyType.ANY:
|
| + if prop.optional:
|
| + c.Append('%(dst)s->%(name)s.reset(new Any());')
|
| + c.Append(self._any_helper.Init(prop, value_var, dst) + ';')
|
| elif prop.type_ == PropertyType.ARRAY:
|
| # util_cc_helper deals with optional and required arrays
|
| (c.Append('ListValue* list = NULL;')
|
| @@ -442,7 +492,7 @@ class CCGenerator(object):
|
| 'dst': dst,
|
| 'failure_value': failure_value,
|
| }
|
| - if prop.type_ != PropertyType.CHOICES:
|
| + if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY):
|
| sub['ctype'] = self._cpp_type_generator.GetType(prop)
|
| sub['value_type'] = cpp_util.GetValueType(prop)
|
| c.Substitute(sub)
|
| @@ -459,20 +509,24 @@ class CCGenerator(object):
|
| param_namespace + '::' + cpp_util.Classname(param.name),
|
| param))
|
| c.Append()
|
| + elif param.type_ == PropertyType.CHOICES:
|
| + c.Concat(self._GeneratePropertyFunctions(
|
| + param_namespace, param.choices.values()))
|
| elif param.type_ == PropertyType.ENUM:
|
| c.Concat(self._GenerateCreateEnumValue(param_namespace, param))
|
| c.Append()
|
| return c
|
|
|
| - def _GenerateFunctionResultCreate(self, function):
|
| + def _GenerateFunctionResultCreate(self, cpp_namespace, function):
|
| """Generate function to create a Result given the return value.
|
| +
|
| + E.g for function "Bar", generate Bar::Result::Create
|
| """
|
| - classname = cpp_util.Classname(function.name)
|
| c = code.Code()
|
| params = function.callback.params
|
|
|
| if not params:
|
| - (c.Append('Value* %s::Result::Create() {' % classname)
|
| + (c.Append('Value* %s::Result::Create() {' % cpp_namespace)
|
| .Append(' return Value::CreateNullValue();')
|
| .Append('}')
|
| )
|
| @@ -480,22 +534,26 @@ class CCGenerator(object):
|
| expanded_params = self._cpp_type_generator.GetExpandedChoicesInParams(
|
| params)
|
| c.Concat(self._GeneratePropertyFunctions(
|
| - classname + '::Result', expanded_params))
|
| + cpp_namespace + '::Result', expanded_params))
|
|
|
| # If there is a single parameter, this is straightforward. However, if
|
| # the callback parameter is of 'choices', this generates a Create method
|
| # for each choice. This works because only 1 choice can be returned at a
|
| # time.
|
| for param in expanded_params:
|
| + if param.type_ == PropertyType.ANY:
|
| + # Generation of Value* Create(Value*) is redundant.
|
| + continue
|
| # We treat this argument as 'required' to avoid wrapping it in a
|
| # scoped_ptr if it's optional.
|
| param_copy = param.Copy()
|
| param_copy.optional = False
|
| - c.Sblock('Value* %(classname)s::Result::Create(const %(arg)s) {')
|
| + c.Sblock('Value* %(cpp_namespace)s::Result::Create(const %(arg)s) {')
|
| c.Append('return %s;' %
|
| self._CreateValueFromProperty(param_copy, param_copy.unix_name))
|
| c.Eblock('}')
|
| - c.Substitute({'classname': classname,
|
| + c.Substitute({
|
| + 'cpp_namespace': cpp_namespace,
|
| 'arg': cpp_util.GetParameterDeclaration(
|
| param_copy, self._cpp_type_generator.GetType(param_copy))
|
| })
|
| @@ -505,6 +563,8 @@ class CCGenerator(object):
|
| def _InitializePropertyToDefault(self, prop, dst):
|
| """Initialize a model.Property to its default value inside an object.
|
|
|
| + E.g for optional enum "state", generate dst->state = STATE_NONE;
|
| +
|
| dst: Type*
|
| """
|
| c = code.Code()
|
|
|