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 cc9214e31342d93a7189605222c9d128cb0fbea5..bbda061682dafb624308865cf1bb171dc7521853 100644 |
--- a/tools/json_schema_compiler/cc_generator.py |
+++ b/tools/json_schema_compiler/cc_generator.py |
@@ -72,19 +72,23 @@ class CCGenerator(object): |
# TODO(calamity): Events |
return c |
- def _GenerateType(self, cpp_namespace, type_, serializable=True): |
+ def _GenerateType(self, cpp_namespace, type_): |
"""Generates the function definitions for a type. |
""" |
classname = cpp_util.Classname(type_.name) |
c = code.Code() |
- (c.Append('%(namespace)s::%(classname)s() {}') |
+ (c.Concat(self._GeneratePropertyFunctions( |
+ cpp_namespace, type_.properties.values())) |
+ .Append('%(namespace)s::%(classname)s() {}') |
.Append('%(namespace)s::~%(classname)s() {}') |
.Append() |
- .Concat(self._GenerateTypePopulate(cpp_namespace, type_)) |
- .Append() |
) |
- if serializable: |
+ if type_.from_json: |
+ (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_)) |
+ .Append() |
+ ) |
+ if type_.from_client: |
c.Concat(self._GenerateTypeToValue(cpp_namespace, type_)) |
c.Append() |
c.Substitute({'classname': classname, 'namespace': cpp_namespace}) |
@@ -129,7 +133,7 @@ class CCGenerator(object): |
'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {' |
) |
.Concat(self._GeneratePopulatePropertyFromValue( |
- prop, value_var, 'out', 'false')) |
+ prop, value_var, dst, 'false')) |
.Eblock('}') |
) |
else: |
@@ -137,7 +141,7 @@ class CCGenerator(object): |
'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') |
.Append(' return false;') |
.Concat(self._GeneratePopulatePropertyFromValue( |
- prop, value_var, 'out', 'false')) |
+ prop, value_var, dst, 'false')) |
) |
c.Append() |
c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) |
@@ -153,50 +157,23 @@ class CCGenerator(object): |
.Append() |
) |
for prop in type_.properties.values(): |
- c.Concat(self._CreateValueFromProperty(prop, prop.unix_name, 'value')) |
+ 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 _CreateValueFromProperty(self, prop, var, dst): |
- """Generates code to serialize a single property in a type. |
- |
- prop: Property to create from |
- var: variable with value to create from |
- """ |
- c = code.Code() |
- if prop.type_ == PropertyType.ENUM: |
- c.Sblock('switch (%s) {' % var) |
- for enum_value in prop.enum_values: |
- (c.Append('case %s: {' % |
- self._cpp_type_generator.GetEnumValue(prop, enum_value)) |
- .Append(' %s->SetWithoutPathExpansion(' |
- '"%s", Value::CreateStringValue("%s"));' % |
- (dst, prop.name, enum_value)) |
- .Append(' break;') |
- .Append('}') |
- ) |
- # C++ requires the entire enum to be handled by a switch. |
- if prop.optional: |
- (c.Append('case %s: {' % |
- self._cpp_type_generator.GetEnumNoneValue(prop)) |
- .Append(' break;') |
- .Append('}') |
- ) |
- c.Eblock('}') |
- else: |
- if prop.optional: |
- c.Sblock('if (%s.get())' % var) |
- if prop.type_ == PropertyType.ARRAY: |
- 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))) |
- return c |
- |
def _GenerateFunction(self, function): |
"""Generates the definitions for function structs. |
""" |
@@ -205,13 +182,8 @@ class CCGenerator(object): |
# Params::Populate function |
if function.params: |
- for param in function.params: |
- if param.type_ == PropertyType.OBJECT: |
- param_namespace = '%s::Params::%s' % (classname, |
- cpp_util.Classname(param.name)) |
- c.Concat( |
- self._GenerateType(param_namespace, param, serializable=False)) |
- c.Append() |
+ c.Concat(self._GeneratePropertyFunctions(classname + '::Params', |
+ function.params)) |
(c.Append('%(name)s::Params::Params() {}') |
.Append('%(name)s::Params::~Params() {}') |
.Append() |
@@ -220,12 +192,81 @@ class CCGenerator(object): |
) |
# Result::Create function |
- c.Concat(self._GenerateFunctionResultCreate(function)) |
+ if function.callback: |
+ c.Concat(self._GenerateFunctionResultCreate(function)) |
c.Substitute({'name': classname}) |
return c |
+ def _GenerateCreateEnumValue(self, cpp_namespace, prop): |
+ """Generates a function that returns the |StringValue| representation of an |
+ enum. |
+ """ |
+ c = code.Code() |
+ c.Append('// static') |
+ c.Sblock('scoped_ptr<Value> %(cpp_namespace)s::CreateEnumValue(%(arg)s) {') |
+ c.Sblock('switch (%s) {' % prop.unix_name) |
+ if prop.optional: |
+ (c.Append('case %s: {' % self._cpp_type_generator.GetEnumNoneValue(prop)) |
+ .Append(' return scoped_ptr<Value>();') |
+ .Append('}') |
+ ) |
+ for enum_value in prop.enum_values: |
+ (c.Append('case %s: {' % |
+ self._cpp_type_generator.GetEnumValue(prop, enum_value)) |
+ .Append(' return scoped_ptr<Value>(Value::CreateStringValue("%s"));' % |
+ enum_value) |
+ .Append('}') |
+ ) |
+ (c.Append('default: {') |
+ .Append(' return scoped_ptr<Value>();') |
+ .Append('}') |
+ ) |
+ c.Eblock('}') |
+ c.Eblock('}') |
+ c.Substitute({ |
+ 'cpp_namespace': cpp_namespace, |
+ 'arg': cpp_util.GetParameterDeclaration( |
+ prop, self._cpp_type_generator.GetType(prop)) |
+ }) |
+ return c |
+ |
+ def _CreateValueFromProperty(self, prop, var): |
+ """Creates a Value given a single property. Generated code passes ownership |
+ to caller. |
+ |
+ var: variable or variable* |
+ """ |
+ 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. |
+ raise NotImplementedError( |
+ 'Conversion of CHOICES to Value not implemented') |
+ if prop.type_ in (PropertyType.REF, PropertyType.OBJECT): |
+ if prop.optional: |
+ return '%s->ToValue().release()' % var |
+ else: |
+ return '%s.ToValue().release()' % var |
+ elif prop.type_ == PropertyType.ENUM: |
+ return 'CreateEnumValue(%s).release()' % var |
+ elif prop.type_ == PropertyType.ARRAY: |
+ return '%s.release()' % self._util_cc_helper.CreateValueFromArray( |
+ prop, var) |
+ elif prop.type_.is_fundamental: |
+ if prop.optional: |
+ var = '*' + var |
+ return { |
+ PropertyType.STRING: 'Value::CreateStringValue(%s)', |
+ PropertyType.BOOLEAN: 'Value::CreateBooleanValue(%s)', |
+ PropertyType.INTEGER: 'Value::CreateIntegerValue(%s)', |
+ PropertyType.DOUBLE: 'Value::CreateDoubleValue(%s)', |
+ }[prop.type_] % var |
+ else: |
+ raise NotImplementedError('Conversion of %s to Value not ' |
+ 'implemented' % repr(prop.type_)) |
+ |
def _GenerateParamsCheck(self, function, var): |
"""Generates a check for the correct number of arguments when creating |
Params. |
@@ -312,7 +353,7 @@ class CCGenerator(object): |
c = code.Code() |
c.Sblock('{') |
- if check_type: |
+ if check_type and prop.type_ != PropertyType.CHOICES: |
(c.Append('if (!%(value_var)s->IsType(%(value_type)s))') |
.Append(' return %(failure_value)s;') |
) |
@@ -358,7 +399,23 @@ class CCGenerator(object): |
.Append(' return %(failure_value)s;') |
) |
elif prop.type_ == PropertyType.CHOICES: |
- return self._GeneratePopulateChoices(prop, value_var, dst, failure_value) |
+ type_var = '%(dst)s->%(name)s_type' |
+ c.Sblock('switch (%(value_var)s->GetType()) {') |
+ for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]): |
+ (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.GetEnumValue( |
+ prop, choice.type_.name))) |
+ .Append('break;') |
+ .Eblock('}') |
+ ) |
+ (c.Append('default:') |
+ .Append(' return %(failure_value)s;') |
+ ) |
+ c.Eblock('}') |
elif prop.type_ == PropertyType.ENUM: |
(c.Append('std::string enum_temp;') |
.Append('if (!%(value_var)s->GetAsString(&enum_temp))') |
@@ -379,46 +436,32 @@ class CCGenerator(object): |
else: |
raise NotImplementedError(prop.type_) |
c.Eblock('}') |
- c.Substitute({ |
+ sub = { |
'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), |
- }) |
+ } |
+ if prop.type_ != PropertyType.CHOICES: |
+ sub['ctype'] = self._cpp_type_generator.GetType(prop) |
+ sub['value_type'] = cpp_util.GetValueType(prop) |
+ c.Substitute(sub) |
return c |
- def _GeneratePopulateChoices(self, prop, value_var, dst, failure_value): |
- """Generates the code to populate a PropertyType.CHOICES parameter or |
- property. 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|. |
+ def _GeneratePropertyFunctions(self, param_namespace, params): |
+ """Generate the functions for structures generated by a property such as |
+ CreateEnumValue for ENUMs and Populate/ToValue for Params/Result objects. |
""" |
- type_var = '%s->%s_type' % (dst, prop.unix_name) |
- |
c = code.Code() |
- c.Sblock('switch (%s->GetType()) {' % value_var) |
- for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]): |
- (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.GetEnumValue( |
- prop, choice.type_.name))) |
- .Append('break;') |
- .Eblock('}') |
- ) |
- (c.Append('default:') |
- .Append(' return %s;' % failure_value) |
- ) |
- c.Eblock('}') |
+ for param in params: |
+ if param.type_ == PropertyType.OBJECT: |
+ c.Concat(self._GenerateType( |
+ param_namespace + '::' + cpp_util.Classname(param.name), |
+ param)) |
+ c.Append() |
+ elif param.type_ == PropertyType.ENUM: |
+ c.Concat(self._GenerateCreateEnumValue(param_namespace, param)) |
+ c.Append() |
return c |
def _GenerateFunctionResultCreate(self, function): |
@@ -434,31 +477,28 @@ class CCGenerator(object): |
.Append('}') |
) |
else: |
+ expanded_params = self._cpp_type_generator.GetExpandedChoicesInParams( |
+ params) |
+ c.Concat(self._GeneratePropertyFunctions( |
+ classname + '::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 self._cpp_type_generator.GetExpandedChoicesInParams(params): |
+ for param in expanded_params: |
# 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) {') |
- if param_copy.type_ == PropertyType.ARRAY: |
- (c.Append('ListValue* value = new ListValue();') |
- .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_copy, |
- param_copy.unix_name)) |
+ c.Append('return %s;' % |
+ self._CreateValueFromProperty(param_copy, param_copy.unix_name)) |
+ c.Eblock('}') |
c.Substitute({'classname': classname, |
'arg': cpp_util.GetParameterDeclaration( |
param_copy, self._cpp_type_generator.GetType(param_copy)) |
}) |
- c.Eblock('}') |
return c |