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 43d7a5e0d81004d77d68e9903a15b6c5fc38d458..80f56db6998d4d27057d012b6172d81eb29d3299 100644 |
--- a/tools/json_schema_compiler/cc_generator.py |
+++ b/tools/json_schema_compiler/cc_generator.py |
@@ -44,20 +44,23 @@ class CCGenerator(object): |
.Concat(self._cpp_type_generator.GetRootNamespaceStart()) |
.Concat(self._cpp_type_generator.GetNamespaceStart()) |
.Append() |
- .Append('//') |
- .Append('// Types') |
- .Append('//') |
- .Append() |
) |
+ if self._namespace.types: |
+ (c.Append('//') |
+ .Append('// Types') |
+ .Append('//') |
+ .Append() |
+ ) |
for type_ in self._namespace.types.values(): |
(c.Concat(self._GenerateType(type_.name, type_)) |
.Append() |
) |
- (c.Append('//') |
- .Append('// Functions') |
- .Append('//') |
- .Append() |
- ) |
+ if self._namespace.functions: |
+ (c.Append('//') |
+ .Append('// Functions') |
+ .Append('//') |
+ .Append() |
+ ) |
for function in self._namespace.functions.values(): |
(c.Concat(self._GenerateFunction(function)) |
.Append() |
@@ -111,71 +114,33 @@ class CCGenerator(object): |
return c |
def _GenerateTypePopulateProperty(self, prop, src, dst): |
- """Generate the code to populate a single property. |
+ """Generate the code to populate a single property in a type. |
src: DictionaryValue* |
dst: Type* |
""" |
c = code.Code() |
- dst_member = dst + '->' + prop.unix_name |
- if prop.type_ == PropertyType.ARRAY: |
- # util_cc_helper deals with optional and required arrays |
- (c.Append('if (!%s)' % |
- self._util_cc_helper.GetArray(prop, src, prop.name, dst_member)) |
- .Append(' return false;') |
+ value_var = prop.unix_name + '_value' |
+ c.Append('Value* %(value_var)s = NULL;') |
+ if prop.optional: |
+ (c.Sblock( |
+ 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {' |
+ ) |
+ .Concat(self._GeneratePopulatePropertyFromValue( |
+ prop, value_var, 'out', 'false')) |
+ .Eblock('}') |
) |
- elif prop.type_ == PropertyType.CHOICES: |
- value_var = prop.unix_name + '_value' |
- c.Append('Value* %(value_var)s = NULL;') |
- c.Append( |
- 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') |
- if prop.optional: |
- c.Append(' return true;') |
- else: |
- c.Append(' return false;') |
- c.Append() |
- c.Concat(self._GeneratePopulateChoices(prop, value_var, dst, 'false')) |
- c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) |
else: |
- if prop.optional: |
- if prop.type_.is_fundamental: |
- (c.Sblock('{') |
- .Append('%(type)s %(name)s_temp;') |
- .Append('if (%s)' % self._GeneratePopulatePropertyFunctionCall( |
- prop, src, '&%s_temp' % prop.unix_name)) |
- .Append(' out->%(name)s.reset(new %(type)s(%(name)s_temp));') |
- .Eblock('}') |
- ) |
- else: |
- raise NotImplementedError('Optional %s not implemented' % prop.type_) |
- else: |
- (c.Append('if (!%s)' % |
- self._GeneratePopulatePropertyFunctionCall( |
- prop, src, '&' + dst_member)) |
- .Append(' return false;') |
- ) |
- c.Substitute({ |
- 'name': prop.unix_name, |
- 'type': self._cpp_type_generator.GetType(prop) |
- }) |
+ (c.Append( |
+ 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') |
+ .Append(' return false;') |
+ .Concat(self._GeneratePopulatePropertyFromValue( |
+ prop, value_var, 'out', 'false')) |
+ ) |
+ c.Append() |
+ c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) |
return c |
- def _GeneratePopulatePropertyFunctionCall(self, prop, src, dst): |
- """Generates the function call that populates the given property. |
- |
- src: DictionaryValue* |
- dst: Property* or scoped_ptr<Property> |
- """ |
- if prop.type_.is_fundamental: |
- populate_line = cpp_util.GetFundamentalValue( |
- prop, src, prop.name, dst) |
- elif prop.type_ in (PropertyType.REF, PropertyType.OBJECT): |
- populate_line = '%(type)s::Populate(*%(src)s, %(dst)s)' |
- else: |
- raise NotImplementedError('%s populate is not implemented' % |
- prop.type_) |
- return populate_line |
- |
def _GenerateTypeToValue(self, cpp_namespace, type_): |
"""Generates a function that serializes the type into a |DictionaryValue|. |
""" |
@@ -203,7 +168,8 @@ class CCGenerator(object): |
if prop.optional: |
c.Sblock('if (%s.get())' % var) |
if prop.type_ == PropertyType.ARRAY: |
- c.Append('%s;' % self._util_cc_helper.SetArray(prop, var, prop.name, dst)) |
+ c.Append('%s;' % self._util_cc_helper.PopulateDictionaryFromArray( |
+ prop, var, prop.name, dst)) |
else: |
c.Append('%s->SetWithoutPathExpansion("%s", %s);' % |
(dst, prop.name, cpp_util.CreateValueFromSingleProperty(prop, var))) |
@@ -250,7 +216,7 @@ class CCGenerator(object): |
if num_required == len(function.params): |
c.Append('if (%(var)s.GetSize() != %(total)d)') |
elif not num_required: |
- c.Append('if (%(var)s.GetSize() > %(total)s)') |
+ c.Append('if (%(var)s.GetSize() > %(total)d)') |
else: |
c.Append('if (%(var)s.GetSize() < %(required)d' |
' || %(var)s.GetSize() > %(total)d)') |
@@ -263,7 +229,8 @@ class CCGenerator(object): |
return c |
def _GenerateFunctionParamsCreate(self, function): |
- """Generate function to create an instance of Params given a pointer. |
+ """Generate function to create an instance of Params. The generated |
+ function takes a ListValue of arguments. |
""" |
classname = cpp_util.Classname(function.name) |
c = code.Code() |
@@ -276,96 +243,120 @@ class CCGenerator(object): |
c.Substitute({'classname': classname}) |
for i, param in enumerate(function.params): |
- dst = 'params->' + param.unix_name |
# Any failure will cause this function to return. If any argument is |
# incorrect or missing, those following it are not processed. Note that |
# this is still correct in the case of multiple optional arguments as an |
# optional argument at position 4 cannot exist without an argument at |
# position 3. |
+ failure_value = 'scoped_ptr<Params>()' |
if param.optional: |
- failure_value = 'params.Pass()' |
+ arg_missing_value = 'params.Pass()' |
else: |
- failure_value = 'scoped_ptr<Params>()' |
+ arg_missing_value = failure_value |
c.Append() |
- param_var = param.unix_name + '_param' |
- # TODO(calamity): Return error on incorrect argument type |
- if param.type_ == PropertyType.ARRAY: |
- # util_cc_helper deals with optional and required arrays |
- (c.Append('ListValue* %(param_var)s = NULL;') |
- .Append('if (!args.GetList(%(i)d, &%(param_var)s))') |
- .Append(' return %s;' % failure_value) |
- .Append('if (!%s)' % self._util_cc_helper.GetArrayFromList( |
- param, param_var, dst)) |
- .Append(' return %s;' % failure_value) |
- ) |
- c.Substitute({'param_var': param_var, 'i': i}) |
- elif param.type_ == PropertyType.CHOICES: |
- value_var = param.unix_name + '_value' |
- (c.Append('Value* %(value_var)s = NULL;') |
- .Append('if (!args.Get(%(i)s, &%(value_var)s))') |
- .Append(' return %s;' % failure_value) |
- .Append() |
- .Concat(self._GeneratePopulateChoices(param, value_var, 'params', |
- 'scoped_ptr<Params>()')) |
- ) |
- c.Substitute({'value_var': value_var, 'i': i}) |
- else: |
- if param.optional: |
- dst = dst + '.get()' |
- else: |
- dst = '&' + dst |
- if param.type_ in (PropertyType.REF, PropertyType.OBJECT): |
- (c.Append('DictionaryValue* %s = NULL;' % param_var) |
- .Append('if (!args.GetDictionary(%d, &%s))' % (i, param_var)) |
- .Append(' return %s;' % failure_value) |
- ) |
- if param.optional: |
- c.Append('params->%s.reset(new %s());' % |
- (param.unix_name, cpp_util.Classname(param.name))) |
- (c.Append('if (!%(ctype)s::Populate(*%(var)s, %(dst)s))' % { |
- 'var': param_var, 'dst': dst, |
- 'ctype': self._cpp_type_generator.GetType(param) |
- }) |
- .Append(' return %s;' % failure_value) |
- ) |
- elif param.type_.is_fundamental: |
- if param.optional: |
- (c.Sblock('{') |
- .Append('%(type)s %(name)s_temp;') |
- .Append('if (%s)' % cpp_util.GetValueFromList( |
- param, 'args', i, '&%s_temp' % param.unix_name)) |
- .Append( |
- ' params->%(name)s.reset(new %(type)s(%(name)s_temp));') |
- .Eblock('}') |
- ) |
- c.Substitute({ |
- 'name': param.unix_name, |
- 'type': self._cpp_type_generator.GetType(param), |
- }) |
- else: |
- (c.Append( |
- 'if (!%s)' % cpp_util.GetValueFromList(param, 'args', i, dst)) |
- .Append(' return %s;' % failure_value) |
- ) |
- else: |
- raise NotImplementedError('%s parameter is not supported' % |
- param.type_) |
+ value_var = param.unix_name + '_value' |
+ (c.Append('Value* %(value_var)s = NULL;') |
+ .Append('if (!args.Get(%(i)s, &%(value_var)s) || ' |
+ '%(value_var)s->IsType(Value::TYPE_NULL))') |
+ .Append(' return %s;' % arg_missing_value) |
+ .Concat(self._GeneratePopulatePropertyFromValue( |
+ param, value_var, 'params', failure_value)) |
+ ) |
+ c.Substitute({'value_var': value_var, 'i': i}) |
(c.Append() |
.Append('return params.Pass();') |
.Eblock('}') |
+ .Append() |
) |
return c |
+ def _GeneratePopulatePropertyFromValue( |
+ self, prop, value_var, dst, failure_value, check_type=True): |
+ """Generates code to populate a model.Property given a Value*. The |
+ existence of data inside the Value* is assumed so checks for existence |
+ should be performed before the code this generates. |
+ |
+ prop: the property the code is populating. |
+ value_var: a Value* that should represent |prop|. |
+ dst: the object with |prop| as a member. |
+ failure_value: the value to return if |prop| cannot be extracted from |
+ |value_var| |
+ check_type: if true, will check if |value_var| is the correct Value::Type |
+ """ |
+ c = code.Code() |
+ c.Sblock('{') |
+ |
+ if check_type: |
+ (c.Append('if (!%(value_var)s->IsType(%(value_type)s))') |
+ .Append(' return %(failure_value)s;') |
+ ) |
+ |
+ if prop.type_.is_fundamental: |
+ if prop.optional: |
+ (c.Append('%(ctype)s temp;') |
+ .Append('if (%s)' % |
+ cpp_util.GetAsFundamentalValue(prop, value_var, '&temp')) |
+ .Append(' %(dst)s->%(name)s.reset(new %(ctype)s(temp));') |
+ ) |
+ else: |
+ (c.Append('if (!%s)' % |
+ cpp_util.GetAsFundamentalValue( |
+ prop, value_var, '&%s->%s' % (dst, prop.unix_name))) |
+ .Append('return %(failure_value)s;') |
+ ) |
+ elif prop.type_ in (PropertyType.OBJECT, PropertyType.REF): |
+ if prop.optional: |
+ (c.Append('DictionaryValue* dictionary = NULL;') |
+ .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') |
+ .Append(' return %(failure_value)s;') |
+ .Append('scoped_ptr<%(ctype)s> temp(new %(ctype)s());') |
+ .Append('if (!%(ctype)s::Populate(*dictionary, temp.get()))') |
+ .Append(' return %(failure_value)s;') |
+ .Append('%(dst)s->%(name)s = temp.Pass();') |
+ ) |
+ else: |
+ (c.Append('DictionaryValue* dictionary = NULL;') |
+ .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') |
+ .Append(' return %(failure_value)s;') |
+ .Append( |
+ 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))') |
+ .Append(' return %(failure_value)s;') |
+ ) |
+ elif prop.type_ == PropertyType.ARRAY: |
+ # util_cc_helper deals with optional and required arrays |
+ (c.Append('ListValue* list = NULL;') |
+ .Append('if (!%(value_var)s->GetAsList(&list))') |
+ .Append(' return %s;' % failure_value) |
+ .Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList( |
+ prop, 'list', dst + '->' + prop.unix_name)) |
+ .Append(' return %s;' % failure_value) |
+ ) |
+ elif prop.type_ == PropertyType.CHOICES: |
+ return self._GeneratePopulateChoices(prop, value_var, dst, failure_value) |
+ else: |
+ raise NotImplementedError(prop.type_) |
+ c.Eblock('}') |
+ c.Substitute({ |
+ 'value_var': value_var, |
+ 'name': prop.unix_name, |
+ 'dst': dst, |
+ 'ctype': self._cpp_type_generator.GetType(prop), |
+ 'failure_value': failure_value, |
+ 'value_type': cpp_util.GetValueType(prop), |
+ }) |
+ return c |
+ |
def _GeneratePopulateChoices(self, prop, value_var, dst, failure_value): |
"""Generates the code to populate a PropertyType.CHOICES parameter or |
- property. |
+ property. The existence of data inside the Value* is assumed so checks for |
+ existence should be performed before the code this generates. |
- value_var: Value* |
- dst: Type* or scoped_ptr<Params> |
- failure_value: the value to return on failure. Check if the property is |
- optional BEFORE the code generated by this method as failure_value will be |
- used to indicate a parsing error. |
+ prop: the property the code is populating.. |
+ value_var: a Value* that should represent |prop|. |
+ dst: the object with |prop| as a member. |
+ failure_value: the value to return if |prop| cannot be extracted from |
+ |value_var| |
""" |
type_var = '%s->%s_type' % (dst, prop.unix_name) |
@@ -374,48 +365,19 @@ class CCGenerator(object): |
(type_var, self._cpp_type_generator.GetChoiceEnumNoneValue(prop))) |
c.Sblock('switch (%s->GetType()) {' % value_var) |
for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]): |
- current_choice = '%s->%s' % (dst, choice.unix_name) |
- if choice.type_.is_fundamental: |
- c.Sblock('case %s: {' % { |
- PropertyType.STRING: 'Value::TYPE_STRING', |
- PropertyType.INTEGER: 'Value::TYPE_INTEGER', |
- PropertyType.BOOLEAN: 'Value::TYPE_BOOLEAN', |
- PropertyType.DOUBLE: 'Value::TYPE_DOUBLE' |
- }[choice.type_]) |
- |
- (c.Append('%(type_var)s = %(enum_value)s;') |
- .Append('%s.reset(new %s());' % |
- (current_choice, self._cpp_type_generator.GetType(choice))) |
- .Append('if (!%s)' % |
- cpp_util.GetAsFundamentalValue( |
- choice, value_var, current_choice + '.get()')) |
- .Append(' return %s;' % failure_value) |
+ (c.Sblock('case %s: {' % cpp_util.GetValueType(choice)) |
+ .Concat(self._GeneratePopulatePropertyFromValue( |
+ choice, value_var, dst, failure_value, check_type=False)) |
+ .Append('%s = %s;' % |
+ (type_var, |
+ self._cpp_type_generator.GetChoiceEnumValue( |
+ prop, choice.type_))) |
.Append('break;') |
.Eblock('}') |
- ) |
- elif choice.type_ == PropertyType.ARRAY: |
- # util_cc_helper deals with optional and required arrays |
- (c.Sblock('case Value::TYPE_LIST: {') |
- .Append('%(type_var)s = %(enum_value)s;') |
- .Append('if (!%s)' % self._util_cc_helper.GetArrayFromList( |
- choice, |
- 'static_cast<ListValue*>(%s)' % value_var, |
- current_choice)) |
- .Append(' return %s;' % failure_value) |
- .Append('break;') |
- .Eblock('}') |
- ) |
- else: |
- raise NotImplementedError(choice.type_) |
- c.Substitute({ |
- 'type_var': type_var, |
- 'enum_value': self._cpp_type_generator.GetChoiceEnumValue( |
- prop, choice.type_), |
- }) |
- if not prop.optional: |
- (c.Append('default:') |
- .Append(' return %s;' % failure_value) |
) |
+ (c.Append('default:') |
+ .Append(' return %s;' % failure_value) |
+ ) |
c.Eblock('}') |
return c |
@@ -425,6 +387,7 @@ class CCGenerator(object): |
classname = cpp_util.Classname(function.name) |
c = code.Code() |
params = function.callback.params |
+ |
if not params: |
(c.Append('Value* %s::Result::Create() {' % classname) |
.Append(' return Value::CreateNullValue();') |
@@ -436,19 +399,25 @@ class CCGenerator(object): |
# for each choice. This works because only 1 choice can be returned at a |
# time. |
for param in self._cpp_type_generator.GetExpandedChoicesInParams(params): |
- arg = cpp_util.GetConstParameterDeclaration( |
- param, self._cpp_type_generator) |
+ # 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(%(arg)s) {') |
- if param.type_ == PropertyType.ARRAY: |
+ if param_copy.type_ == PropertyType.ARRAY: |
(c.Append('ListValue* value = new ListValue();') |
- .Append('%s;' % self._util_cc_helper.SetArrayToList( |
- param, param.unix_name, 'value')) |
+ .Append('%s;' % self._util_cc_helper.PopulateListFromArray( |
+ param_copy, param_copy.unix_name, 'value')) |
.Append('return value;') |
) |
else: |
- c.Append('return %s;' % cpp_util.CreateValueFromSingleProperty(param, |
- param.unix_name)) |
- c.Substitute({'classname': classname, 'arg': arg}) |
+ c.Append('return %s;' % |
+ cpp_util.CreateValueFromSingleProperty(param_copy, |
+ param_copy.unix_name)) |
+ c.Substitute({'classname': classname, |
+ 'arg': cpp_util.GetParameterDeclaration( |
+ param_copy, self._cpp_type_generator.GetType(param_copy)) |
+ }) |
c.Eblock('}') |
return c |