Added JSON schema compiler support for serialized types

Currently supports string->int, string->int64, and int->string.

BUG=139076


Review URL: https://chromiumcodereview.appspot.com/10825029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149302 0039d316-1c4b-4281-b951-d872f2087c98
parent 0933b60e
...@@ -253,20 +253,36 @@ class CCGenerator(object): ...@@ -253,20 +253,36 @@ class CCGenerator(object):
else: else:
if prop.optional: if prop.optional:
if prop.type_ == PropertyType.ENUM: if prop.type_ == PropertyType.ENUM:
c.Sblock('if (%s != %s)' % c.Sblock('if (%s != %s) {' %
(prop.unix_name, (prop.unix_name,
self._cpp_type_generator.GetEnumNoneValue(prop))) self._cpp_type_generator.GetEnumNoneValue(prop)))
elif prop.type_ == PropertyType.CHOICES: elif prop.type_ == PropertyType.CHOICES:
c.Sblock('if (%s_type != %s)' % c.Sblock('if (%s_type != %s) {' %
(prop.unix_name, (prop.unix_name,
self._cpp_type_generator.GetEnumNoneValue(prop))) self._cpp_type_generator.GetEnumNoneValue(prop)))
else: else:
c.Sblock('if (%s.get())' % prop.unix_name) c.Sblock('if (%s.get()) {' % prop.unix_name)
c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
prop.name, if prop.type_ == prop.compiled_type:
self._CreateValueFromProperty(prop, 'this->' + prop.unix_name))) c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
prop.name,
self._CreateValueFromProperty(prop, 'this->' + prop.unix_name)))
else:
conversion_src = 'this->' + prop.unix_name
if prop.optional:
conversion_src = '*' + conversion_src
(c.Append('%s %s;' % (self._cpp_type_generator.GetType(prop),
prop.unix_name))
.Append(cpp_util.GenerateCompiledTypeToTypeConversion(
self._cpp_type_generator.GetReferencedProperty(prop),
conversion_src,
prop.unix_name) + ';')
.Append('value->SetWithoutPathExpansion("%s", %s);' % (
prop.unix_name,
self._CreateValueFromProperty(prop, prop.unix_name)))
)
if prop.optional: if prop.optional:
c.Eblock(); c.Eblock('}');
(c.Append() (c.Append()
.Append('return value.Pass();') .Append('return value.Pass();')
.Eblock('}') .Eblock('}')
...@@ -337,7 +353,11 @@ class CCGenerator(object): ...@@ -337,7 +353,11 @@ class CCGenerator(object):
self._cpp_type_generator.GetReferencedProperty(prop), var, self._cpp_type_generator.GetReferencedProperty(prop), var,
prop.optional) prop.optional)
elif self._IsFundamentalOrFundamentalRef(prop): elif self._IsFundamentalOrFundamentalRef(prop):
if prop.optional: # If prop.type != prop.compiled_type, then no asterisk is necessary
# because the target is a local variable and not a dereferenced scoped
# pointer. The asterisk is instead prepended to conversion_src around line
# 273.
if prop.optional and prop.type_ == prop.compiled_type:
var = '*' + var var = '*' + var
prop = self._cpp_type_generator.GetReferencedProperty(prop); prop = self._cpp_type_generator.GetReferencedProperty(prop);
return { return {
...@@ -448,16 +468,42 @@ class CCGenerator(object): ...@@ -448,16 +468,42 @@ class CCGenerator(object):
value_var, value_var,
'&temp')) '&temp'))
.Append(' return %(failure_value)s;') .Append(' return %(failure_value)s;')
.Append('%(dst)s->%(name)s.reset(new %(ctype)s(temp));')
) )
if prop.type_ != prop.compiled_type:
(c.Append('%(compiled_ctype)s temp2;')
.Append('if (!%s)' %
cpp_util.GenerateTypeToCompiledTypeConversion(
self._cpp_type_generator.GetReferencedProperty(prop),
'temp',
'temp2'))
.Append(' return %(failure_value)s;')
.Append('%(dst)s->%(name)s.reset(new %(compiled_ctype)s(temp2));')
)
else:
c.Append('%(dst)s->%(name)s.reset(new %(ctype)s(temp));')
else: else:
if prop.type_ == prop.compiled_type:
assignment_target = '&%s->%s' % (dst, prop.unix_name)
else:
c.Append('%(ctype)s temp;')
assignment_target = '&temp'
(c.Append('if (!%s)' % (c.Append('if (!%s)' %
cpp_util.GetAsFundamentalValue( cpp_util.GetAsFundamentalValue(
self._cpp_type_generator.GetReferencedProperty(prop), self._cpp_type_generator.GetReferencedProperty(prop),
value_var, value_var,
'&%s->%s' % (dst, prop.unix_name))) assignment_target))
.Append(' return %(failure_value)s;') .Append(' return %(failure_value)s;')
) )
if prop.type_ != prop.compiled_type:
(c.Append('if (!%s)' %
cpp_util.GenerateTypeToCompiledTypeConversion(
self._cpp_type_generator.GetReferencedProperty(prop),
'temp',
'%s->%s' % (dst, prop.unix_name)))
.Append(' return %(failure_value)s;')
)
elif self._IsObjectOrObjectRef(prop): elif self._IsObjectOrObjectRef(prop):
if prop.optional: if prop.optional:
(c.Append('const base::DictionaryValue* dictionary = NULL;') (c.Append('const base::DictionaryValue* dictionary = NULL;')
...@@ -546,6 +592,7 @@ class CCGenerator(object): ...@@ -546,6 +592,7 @@ class CCGenerator(object):
} }
if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY): if prop.type_ not in (PropertyType.CHOICES, PropertyType.ANY):
sub['ctype'] = self._cpp_type_generator.GetType(prop) sub['ctype'] = self._cpp_type_generator.GetType(prop)
sub['compiled_ctype'] = self._cpp_type_generator.GetCompiledType(prop)
sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator sub['value_type'] = cpp_util.GetValueType(self._cpp_type_generator
.GetReferencedProperty(prop).type_) .GetReferencedProperty(prop).type_)
c.Substitute(sub) c.Substitute(sub)
...@@ -721,10 +768,20 @@ class CCGenerator(object): ...@@ -721,10 +768,20 @@ class CCGenerator(object):
# scoped_ptr if it's optional. # scoped_ptr if it's optional.
param_copy = param.Copy() param_copy = param.Copy()
param_copy.optional = False param_copy.optional = False
c.Append('create_results->Append(%s);' %
self._CreateValueFromProperty(param_copy, param_copy.unix_name))
declaration_list.append("const %s" % cpp_util.GetParameterDeclaration( declaration_list.append("const %s" % cpp_util.GetParameterDeclaration(
param_copy, self._cpp_type_generator.GetType(param_copy))) param_copy, self._cpp_type_generator.GetCompiledType(param_copy)))
param_name = param_copy.unix_name
if param_copy.type_ != param_copy.compiled_type:
param_name = 'temp_' + param_name
(c.Append('%s %s;' % (self._cpp_type_generator.GetType(param_copy),
param_name))
.Append(cpp_util.GenerateCompiledTypeToTypeConversion(
param_copy,
param_copy.unix_name,
param_name) + ';')
)
c.Append('create_results->Append(%s);' %
self._CreateValueFromProperty(param_copy, param_name))
c.Append('return create_results.Pass();') c.Append('return create_results.Pass();')
c.Eblock('}') c.Eblock('}')
......
...@@ -116,6 +116,14 @@ class CppTypeGenerator(object): ...@@ -116,6 +116,14 @@ class CppTypeGenerator(object):
return cpp_util.Classname(prop.name) + 'Type' return cpp_util.Classname(prop.name) + 'Type'
def GetType(self, prop, pad_for_generics=False, wrap_optional=False): def GetType(self, prop, pad_for_generics=False, wrap_optional=False):
return self._GetTypeHelper(prop, pad_for_generics, wrap_optional)
def GetCompiledType(self, prop, pad_for_generics=False, wrap_optional=False):
return self._GetTypeHelper(prop, pad_for_generics, wrap_optional,
use_compiled_type=True)
def _GetTypeHelper(self, prop, pad_for_generics=False, wrap_optional=False,
use_compiled_type=False):
"""Translates a model.Property into its C++ type. """Translates a model.Property into its C++ type.
If REF types from different namespaces are referenced, will resolve If REF types from different namespaces are referenced, will resolve
...@@ -125,9 +133,13 @@ class CppTypeGenerator(object): ...@@ -125,9 +133,13 @@ class CppTypeGenerator(object):
Use wrap_optional to wrap the type in a scoped_ptr<T> if the Property is Use wrap_optional to wrap the type in a scoped_ptr<T> if the Property is
optional. optional.
Use use_compiled_type when converting from prop.type_ to prop.compiled_type.
""" """
cpp_type = None cpp_type = None
if prop.type_ == PropertyType.REF: type_ = prop.type_ if not use_compiled_type else prop.compiled_type
if type_ == PropertyType.REF:
dependency_namespace = self._ResolveTypeNamespace(prop.ref_type) dependency_namespace = self._ResolveTypeNamespace(prop.ref_type)
if not dependency_namespace: if not dependency_namespace:
raise KeyError('Cannot find referenced type: %s' % prop.ref_type) raise KeyError('Cannot find referenced type: %s' % prop.ref_type)
...@@ -136,28 +148,30 @@ class CppTypeGenerator(object): ...@@ -136,28 +148,30 @@ class CppTypeGenerator(object):
schema_util.StripSchemaNamespace(prop.ref_type)) schema_util.StripSchemaNamespace(prop.ref_type))
else: else:
cpp_type = schema_util.StripSchemaNamespace(prop.ref_type) cpp_type = schema_util.StripSchemaNamespace(prop.ref_type)
elif prop.type_ == PropertyType.BOOLEAN: elif type_ == PropertyType.BOOLEAN:
cpp_type = 'bool' cpp_type = 'bool'
elif prop.type_ == PropertyType.INTEGER: elif type_ == PropertyType.INTEGER:
cpp_type = 'int' cpp_type = 'int'
elif prop.type_ == PropertyType.DOUBLE: elif type_ == PropertyType.INT64:
cpp_type = 'int64'
elif type_ == PropertyType.DOUBLE:
cpp_type = 'double' cpp_type = 'double'
elif prop.type_ == PropertyType.STRING: elif type_ == PropertyType.STRING:
cpp_type = 'std::string' cpp_type = 'std::string'
elif prop.type_ == PropertyType.ENUM: elif type_ == PropertyType.ENUM:
cpp_type = cpp_util.Classname(prop.name) cpp_type = cpp_util.Classname(prop.name)
elif prop.type_ == PropertyType.ADDITIONAL_PROPERTIES: elif type_ == PropertyType.ADDITIONAL_PROPERTIES:
cpp_type = 'base::DictionaryValue' cpp_type = 'base::DictionaryValue'
elif prop.type_ == PropertyType.ANY: elif type_ == PropertyType.ANY:
cpp_type = any_helper.ANY_CLASS cpp_type = any_helper.ANY_CLASS
elif prop.type_ == PropertyType.OBJECT: elif type_ == PropertyType.OBJECT:
cpp_type = cpp_util.Classname(prop.name) cpp_type = cpp_util.Classname(prop.name)
elif prop.type_ == PropertyType.FUNCTION: elif type_ == PropertyType.FUNCTION:
# Functions come into the json schema compiler as empty objects. We can # Functions come into the json schema compiler as empty objects. We can
# record these as empty DictionaryValue's so that we know if the function # record these as empty DictionaryValue's so that we know if the function
# was passed in or not. # was passed in or not.
cpp_type = 'base::DictionaryValue' cpp_type = 'base::DictionaryValue'
elif prop.type_ == PropertyType.ARRAY: elif type_ == PropertyType.ARRAY:
item_type = prop.item_type item_type = prop.item_type
if item_type.type_ == PropertyType.REF: if item_type.type_ == PropertyType.REF:
item_type = self.GetReferencedProperty(item_type) item_type = self.GetReferencedProperty(item_type)
...@@ -168,14 +182,14 @@ class CppTypeGenerator(object): ...@@ -168,14 +182,14 @@ class CppTypeGenerator(object):
cpp_type = 'std::vector<%s> ' cpp_type = 'std::vector<%s> '
cpp_type = cpp_type % self.GetType( cpp_type = cpp_type % self.GetType(
prop.item_type, pad_for_generics=True) prop.item_type, pad_for_generics=True)
elif prop.type_ == PropertyType.BINARY: elif type_ == PropertyType.BINARY:
cpp_type = 'std::string' cpp_type = 'std::string'
else: else:
raise NotImplementedError(prop.type_) raise NotImplementedError(type_)
# Enums aren't wrapped because C++ won't allow it. Optional enums have a # Enums aren't wrapped because C++ won't allow it. Optional enums have a
# NONE value generated instead. # NONE value generated instead.
if wrap_optional and prop.optional and prop.type_ != PropertyType.ENUM: if wrap_optional and prop.optional and type_ != PropertyType.ENUM:
cpp_type = 'scoped_ptr<%s> ' % cpp_type cpp_type = 'scoped_ptr<%s> ' % cpp_type
if pad_for_generics: if pad_for_generics:
return cpp_type return cpp_type
...@@ -222,6 +236,8 @@ class CppTypeGenerator(object): ...@@ -222,6 +236,8 @@ class CppTypeGenerator(object):
self._cpp_namespaces[dependency]) self._cpp_namespaces[dependency])
for dependency in self._NamespaceTypeDependencies().keys()]): for dependency in self._NamespaceTypeDependencies().keys()]):
c.Append('#include "%s"' % header) c.Append('#include "%s"' % header)
c.Append('#include "base/string_number_conversions.h"')
if self._namespace.events: if self._namespace.events:
c.Append('#include "base/json/json_writer.h"') c.Append('#include "base/json/json_writer.h"')
return c return c
......
...@@ -48,6 +48,7 @@ class CppTypeGeneratorTest(unittest.TestCase): ...@@ -48,6 +48,7 @@ class CppTypeGeneratorTest(unittest.TestCase):
manager = CppTypeGenerator('', self.windows, self.windows.unix_name) manager = CppTypeGenerator('', self.windows, self.windows.unix_name)
manager.AddNamespace(self.tabs, self.tabs.unix_name) manager.AddNamespace(self.tabs, self.tabs.unix_name)
self.assertEquals('#include "path/to/tabs.h"\n' self.assertEquals('#include "path/to/tabs.h"\n'
'#include "base/string_number_conversions.h"\n'
'#include "base/json/json_writer.h"', '#include "base/json/json_writer.h"',
manager.GenerateIncludes().Render()) manager.GenerateIncludes().Render())
self.assertEquals('namespace tabs {\n' self.assertEquals('namespace tabs {\n'
...@@ -58,7 +59,8 @@ class CppTypeGeneratorTest(unittest.TestCase): ...@@ -58,7 +59,8 @@ class CppTypeGeneratorTest(unittest.TestCase):
'} // windows', '} // windows',
manager.GenerateForwardDeclarations().Render()) manager.GenerateForwardDeclarations().Render())
manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name) manager = CppTypeGenerator('', self.permissions, self.permissions.unix_name)
self.assertEquals('#include "base/json/json_writer.h"', self.assertEquals('#include "base/string_number_conversions.h"\n'
'#include "base/json/json_writer.h"',
manager.GenerateIncludes().Render()) manager.GenerateIncludes().Render())
self.assertEquals('namespace permissions {\n' self.assertEquals('namespace permissions {\n'
'struct Permissions;\n' 'struct Permissions;\n'
...@@ -66,7 +68,8 @@ class CppTypeGeneratorTest(unittest.TestCase): ...@@ -66,7 +68,8 @@ class CppTypeGeneratorTest(unittest.TestCase):
manager.GenerateForwardDeclarations().Render()) manager.GenerateForwardDeclarations().Render())
manager = CppTypeGenerator('', self.content_settings, manager = CppTypeGenerator('', self.content_settings,
self.content_settings.unix_name) self.content_settings.unix_name)
self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('#include "base/string_number_conversions.h"',
manager.GenerateIncludes().Render())
def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self): def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self):
...@@ -83,6 +86,7 @@ class CppTypeGeneratorTest(unittest.TestCase): ...@@ -83,6 +86,7 @@ class CppTypeGeneratorTest(unittest.TestCase):
manager = CppTypeGenerator('', windows, self.windows.unix_name) manager = CppTypeGenerator('', windows, self.windows.unix_name)
manager.AddNamespace(tabs_namespace, self.tabs.unix_name) manager.AddNamespace(tabs_namespace, self.tabs.unix_name)
self.assertEquals('#include "path/to/tabs.h"\n' self.assertEquals('#include "path/to/tabs.h"\n'
'#include "base/string_number_conversions.h"\n'
'#include "base/json/json_writer.h"', '#include "base/json/json_writer.h"',
manager.GenerateIncludes().Render()) manager.GenerateIncludes().Render())
self.assertEquals('namespace tabs {\n' self.assertEquals('namespace tabs {\n'
...@@ -109,7 +113,8 @@ class CppTypeGeneratorTest(unittest.TestCase): ...@@ -109,7 +113,8 @@ class CppTypeGeneratorTest(unittest.TestCase):
manager.AddNamespace(browser_action_namespace, manager.AddNamespace(browser_action_namespace,
self.browser_action.unix_name) self.browser_action.unix_name)
self.assertEquals('#include "path/to/browser_action.h"\n' self.assertEquals('#include "path/to/browser_action.h"\n'
'#include "path/to/font_settings.h"', '#include "path/to/font_settings.h"\n'
'#include "base/string_number_conversions.h"',
manager.GenerateIncludes().Render()) manager.GenerateIncludes().Render())
self.assertEquals('namespace browserAction {\n' self.assertEquals('namespace browserAction {\n'
'typedef std::vector<int> ColorArray;\n' 'typedef std::vector<int> ColorArray;\n'
......
...@@ -75,9 +75,47 @@ def GetParameterDeclaration(param, type_): ...@@ -75,9 +75,47 @@ def GetParameterDeclaration(param, type_):
} }
def GenerateIfndefName(path, filename): def GenerateIfndefName(path, filename):
"""Formats a path and filename as a #define name. """Formats a path and filename as a #define name.
e.g chrome/extensions/gen, file.h becomes CHROME_EXTENSIONS_GEN_FILE_H__. e.g chrome/extensions/gen, file.h becomes CHROME_EXTENSIONS_GEN_FILE_H__.
""" """
return (('%s_%s_H__' % (path, filename)) return (('%s_%s_H__' % (path, filename))
.upper().replace(os.sep, '_').replace('/', '_')) .upper().replace(os.sep, '_').replace('/', '_'))
def GenerateTypeToCompiledTypeConversion(prop, from_, to):
try:
return _GenerateTypeConversionHelper(prop.type_, prop.compiled_type, from_,
to)
except KeyError:
raise NotImplementedError('Conversion from %s to %s in %s not supported' %
(prop.type_, prop.compiled_type, prop.name))
def GenerateCompiledTypeToTypeConversion(prop, from_, to):
try:
return _GenerateTypeConversionHelper(prop.compiled_type, prop.type_, from_,
to)
except KeyError:
raise NotImplementedError('Conversion from %s to %s in %s not supported' %
(prop.compiled_type, prop.type_, prop.name))
def _GenerateTypeConversionHelper(from_type, to_type, from_, to):
"""Converts from PropertyType from_type to PropertyType to_type.
from_type: The PropertyType to be converted from.
to_type: The PropertyType to be converted to.
from_: The variable name of the type to be converted from.
to: The variable name of the type to be converted to.
"""
# TODO(mwrosen): Add support for more from/to combinations as necessary.
return {
PropertyType.STRING: {
PropertyType.INTEGER: 'base::StringToInt(%(from)s, &%(to)s)',
PropertyType.INT64: 'base::StringToInt64(%(from)s, &%(to)s)',
},
PropertyType.INTEGER: {
PropertyType.STRING: '%(to)s = base::IntToString(%(from)s)',
},
PropertyType.INT64: {
PropertyType.STRING: '%(to)s = base::Int64ToString(%(from)s)',
}
}[from_type][to_type] % {'from': from_, 'to': to}
...@@ -159,8 +159,8 @@ class HGenerator(object): ...@@ -159,8 +159,8 @@ class HGenerator(object):
if prop.description: if prop.description:
c.Comment(prop.description) c.Comment(prop.description)
(c.Append('%s %s;' % ( (c.Append('%s %s;' % (
self._cpp_type_generator.GetType(prop, wrap_optional=True), self._cpp_type_generator.GetCompiledType(prop, wrap_optional=True),
prop.unix_name)) prop.unix_name))
.Append() .Append()
) )
return c return c
...@@ -183,8 +183,8 @@ class HGenerator(object): ...@@ -183,8 +183,8 @@ class HGenerator(object):
c.Comment(type_.description) c.Comment(type_.description)
c.Append('typedef std::vector<%(item_type)s> %(classname)s;') c.Append('typedef std::vector<%(item_type)s> %(classname)s;')
c.Substitute({'classname': classname, 'item_type': c.Substitute({'classname': classname, 'item_type':
self._cpp_type_generator.GetType(type_.item_type, self._cpp_type_generator.GetCompiledType(type_.item_type,
wrap_optional=True)}) wrap_optional=True)})
elif type_.type_ == PropertyType.STRING: elif type_.type_ == PropertyType.STRING:
if type_.description: if type_.description:
c.Comment(type_.description) c.Comment(type_.description)
...@@ -294,7 +294,7 @@ class HGenerator(object): ...@@ -294,7 +294,7 @@ class HGenerator(object):
[choice.type_.name for choice in prop.choices.values()])) [choice.type_.name for choice in prop.choices.values()]))
c.Concat(self._GeneratePropertyStructures(prop.choices.values())) c.Concat(self._GeneratePropertyStructures(prop.choices.values()))
elif prop.type_ == PropertyType.ENUM: elif prop.type_ == PropertyType.ENUM:
enum_name = self._cpp_type_generator.GetType(prop) enum_name = self._cpp_type_generator.GetCompiledType(prop)
c.Concat(self._GenerateEnumDeclaration( c.Concat(self._GenerateEnumDeclaration(
enum_name, enum_name,
prop, prop,
...@@ -339,7 +339,7 @@ class HGenerator(object): ...@@ -339,7 +339,7 @@ class HGenerator(object):
if param.description: if param.description:
c.Comment(param.description) c.Comment(param.description)
declaration_list.append('const %s' % cpp_util.GetParameterDeclaration( declaration_list.append('const %s' % cpp_util.GetParameterDeclaration(
param, self._cpp_type_generator.GetType(param))) param, self._cpp_type_generator.GetCompiledType(param)))
c.Append('scoped_ptr<base::ListValue> Create(%s);' % c.Append('scoped_ptr<base::ListValue> Create(%s);' %
', '.join(declaration_list)) ', '.join(declaration_list))
if generate_to_json: if generate_to_json:
......
...@@ -151,6 +151,8 @@ class Property(object): ...@@ -151,6 +151,8 @@ class Property(object):
- |optional| a boolean representing whether the property is optional - |optional| a boolean representing whether the property is optional
- |description| a description of the property (if provided) - |description| a description of the property (if provided)
- |type_| the model.PropertyType of this property - |type_| the model.PropertyType of this property
- |compiled_type| the model.PropertyType that this property should be
compiled to from the JSON. Defaults to |type_|.
- |ref_type| the type that the REF property is referencing. Can be used to - |ref_type| the type that the REF property is referencing. Can be used to
map to its model.Type map to its model.Type
- |item_type| a model.Property representing the type of each element in an - |item_type| a model.Property representing the type of each element in an
...@@ -190,40 +192,23 @@ class Property(object): ...@@ -190,40 +192,23 @@ class Property(object):
self.enum_values.append(value) self.enum_values.append(value)
self.type_ = PropertyType.ENUM self.type_ = PropertyType.ENUM
elif 'type' in json: elif 'type' in json:
json_type = json['type'] self.type_ = self._JsonTypeToPropertyType(json['type'])
if json_type == 'string': if self.type_ == PropertyType.ARRAY:
self.type_ = PropertyType.STRING
elif json_type == 'any':
self.type_ = PropertyType.ANY
elif json_type == 'boolean':
self.type_ = PropertyType.BOOLEAN
elif json_type == 'integer':
self.type_ = PropertyType.INTEGER
elif json_type == 'number':
self.type_ = PropertyType.DOUBLE
elif json_type == 'array':
self.item_type = Property(self, name + "Element", json['items'], self.item_type = Property(self, name + "Element", json['items'],
from_json=from_json, from_json=from_json,
from_client=from_client) from_client=from_client)
self.type_ = PropertyType.ARRAY elif self.type_ == PropertyType.OBJECT:
elif json_type == 'object':
self.type_ = PropertyType.OBJECT
# These members are read when this OBJECT Property is used as a Type # These members are read when this OBJECT Property is used as a Type
type_ = Type(self, self.name, json) type_ = Type(self, self.name, json)
# self.properties will already have some value from |_AddProperties|. # self.properties will already have some value from |_AddProperties|.
self.properties.update(type_.properties) self.properties.update(type_.properties)
self.functions = type_.functions self.functions = type_.functions
elif json_type == 'function':
self.type_ = PropertyType.FUNCTION
elif json_type == 'binary':
self.type_ = PropertyType.BINARY
else:
raise ParseException(self, 'type ' + json_type + ' not recognized')
elif 'choices' in json: elif 'choices' in json:
if not json['choices'] or len(json['choices']) == 0: if not json['choices'] or len(json['choices']) == 0:
raise ParseException(self, 'Choices has no choices') raise ParseException(self, 'Choices has no choices')
self.choices = {} self.choices = {}
self.type_ = PropertyType.CHOICES self.type_ = PropertyType.CHOICES
self.compiled_type = self.type_
for choice_json in json['choices']: for choice_json in json['choices']:
choice = Property(self, self.name, choice_json, choice = Property(self, self.name, choice_json,
from_json=from_json, from_json=from_json,
...@@ -237,6 +222,7 @@ class Property(object): ...@@ -237,6 +222,7 @@ class Property(object):
self.value = json['value'] self.value = json['value']
if type(self.value) == int: if type(self.value) == int:
self.type_ = PropertyType.INTEGER self.type_ = PropertyType.INTEGER
self.compiled_type = self.type_
else: else:
# TODO(kalman): support more types as necessary. # TODO(kalman): support more types as necessary.
raise ParseException( raise ParseException(
...@@ -244,6 +230,30 @@ class Property(object): ...@@ -244,6 +230,30 @@ class Property(object):
else: else:
raise ParseException( raise ParseException(
self, 'Property has no type, $ref, choices, or value') self, 'Property has no type, $ref, choices, or value')
if 'compiled_type' in json:
if 'type' in json:
self.compiled_type = self._JsonTypeToPropertyType(json['compiled_type'])
else:
raise ParseException(self, 'Property has compiled_type but no type')
else:
self.compiled_type = self.type_
def _JsonTypeToPropertyType(self, json_type):
try:
return {
'any': PropertyType.ANY,
'array': PropertyType.ARRAY,
'binary': PropertyType.BINARY,
'boolean': PropertyType.BOOLEAN,
'integer': PropertyType.INTEGER,
'int64': PropertyType.INT64,
'function': PropertyType.FUNCTION,
'number': PropertyType.DOUBLE,
'object': PropertyType.OBJECT,
'string': PropertyType.STRING,
}[json_type]
except KeyError:
raise NotImplementedError('Type %s not recognized' % json_type)
def GetUnixName(self): def GetUnixName(self):
"""Gets the property's unix_name. Raises AttributeError if not set. """Gets the property's unix_name. Raises AttributeError if not set.
...@@ -288,6 +298,7 @@ class PropertyType(object): ...@@ -288,6 +298,7 @@ class PropertyType(object):
return self.name return self.name
INTEGER = _Info(True, "INTEGER") INTEGER = _Info(True, "INTEGER")
INT64 = _Info(True, "INT64")
DOUBLE = _Info(True, "DOUBLE") DOUBLE = _Info(True, "DOUBLE")
BOOLEAN = _Info(True, "BOOLEAN") BOOLEAN = _Info(True, "BOOLEAN")
STRING = _Info(True, "STRING") STRING = _Info(True, "STRING")
......
...@@ -66,7 +66,7 @@ class ModelTest(unittest.TestCase): ...@@ -66,7 +66,7 @@ class ModelTest(unittest.TestCase):
def testPropertyNotImplemented(self): def testPropertyNotImplemented(self):
(self.permissions_json[0]['types'][0] (self.permissions_json[0]['types'][0]
['properties']['permissions']['type']) = 'something' ['properties']['permissions']['type']) = 'something'
self.assertRaises(model.ParseException, self.model.AddNamespace, self.assertRaises(NotImplementedError, self.model.AddNamespace,
self.permissions_json[0], 'path/to/something.json') self.permissions_json[0], 'path/to/something.json')
def testDescription(self): def testDescription(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment