diff options
Diffstat (limited to 'tools/json_to_struct')
-rw-r--r-- | tools/json_to_struct/element_generator.py | 80 | ||||
-rwxr-xr-x | tools/json_to_struct/element_generator_test.py | 152 | ||||
-rwxr-xr-x | tools/json_to_struct/json_to_struct.py | 14 | ||||
-rw-r--r-- | tools/json_to_struct/struct_generator.py | 10 | ||||
-rwxr-xr-x | tools/json_to_struct/struct_generator_test.py | 27 |
5 files changed, 222 insertions, 61 deletions
diff --git a/tools/json_to_struct/element_generator.py b/tools/json_to_struct/element_generator.py index 20d3069..e347532 100644 --- a/tools/json_to_struct/element_generator.py +++ b/tools/json_to_struct/element_generator.py @@ -22,42 +22,54 @@ def _JSONToCString16(json_string_literal): escape_index = c_string_literal.find('\\', escape_index + 6) return c_string_literal -def _GenerateString(content, lines): +def _GenerateString(content, lines, indent=' '): """Generates an UTF-8 string to be included in a static structure initializer. If content is not specified, uses NULL. """ if content is None: - lines.append(' NULL,') + lines.append(indent + 'NULL,') else: # json.dumps quotes the string and escape characters as required. - lines.append(' %s,' % json.dumps(content)) + lines.append(indent + '%s,' % json.dumps(content)) -def _GenerateString16(content, lines): +def _GenerateString16(content, lines, indent=' '): """Generates an UTF-16 string to be included in a static structure initializer. If content is not specified, uses NULL. """ if content is None: - lines.append(' NULL,') + lines.append(indent + 'NULL,') else: # json.dumps quotes the string and escape characters as required. - lines.append(' L%s,' % _JSONToCString16(json.dumps(content))) + lines.append(indent + 'L%s,' % _JSONToCString16(json.dumps(content))) -def _GenerateArray(element_name, field_info, content, lines): +def _GenerateArrayVariableName(element_name, field_name, field_name_count): + # Generates a unique variable name for an array variable. + var = 'array_%s_%s' % (element_name, field_name) + if var not in field_name_count: + field_name_count[var] = 0 + return var + new_var = '%s_%d' % (var, field_name_count[var]) + field_name_count[var] += 1 + return new_var + +def _GenerateArray(element_name, field_info, content, lines, indent, + field_name_count): """Generates an array to be included in a static structure initializer. If content is not specified, uses NULL. The array is assigned to a temporary variable which is initialized before the structure. """ if content is None: - lines.append(' NULL,') - lines.append(' 0,') # Size of the array. + lines.append(indent + 'NULL,') + lines.append(indent + '0,') # Size of the array. return # Create a new array variable and use it in the structure initializer. # This prohibits nested arrays. Add a clash detection and renaming mechanism # to solve the problem. - var = 'array_%s_%s' % (element_name, field_info['field']); - lines.append(' %s,' % var) - lines.append(' %s,' % len(content)) # Size of the array. + var = _GenerateArrayVariableName(element_name, field_info['field'], + field_name_count) + lines.append(indent + '%s,' % var) + lines.append(indent + '%s,' % len(content)) # Size of the array. # Generate the array content. array_lines = [] field_info['contents']['field'] = var; @@ -65,7 +77,7 @@ def _GenerateArray(element_name, field_info, content, lines): field_info['contents']) + '[] = {') for subcontent in content: GenerateFieldContent(element_name, field_info['contents'], subcontent, - array_lines) + array_lines, indent, field_name_count) array_lines.append('};') # Prepend the generated array so it is initialized before the structure. lines.reverse() @@ -73,7 +85,25 @@ def _GenerateArray(element_name, field_info, content, lines): lines.extend(array_lines) lines.reverse() -def GenerateFieldContent(element_name, field_info, content, lines): +def _GenerateStruct(element_name, field_info, content, lines, indent, + field_name_count): + """Generates a struct to be included in a static structure initializer. If + content is not specified, uses {0}. + """ + if content is None: + lines.append(indent + '{0},') + return + + fields = field_info['fields'] + lines.append(indent + '{') + for field in fields: + subcontent = content.get(field['field']) + GenerateFieldContent(element_name, field, subcontent, lines, ' ' + indent, + field_name_count) + lines.append(indent + '},') + +def GenerateFieldContent(element_name, field_info, content, lines, indent, + field_name_count): """Generate the content of a field to be included in the static structure initializer. If the field's content is not specified, uses the default value if one exists. @@ -82,17 +112,21 @@ def GenerateFieldContent(element_name, field_info, content, lines): content = field_info.get('default', None) type = field_info['type'] if type == 'int' or type == 'enum': - lines.append(' %s,' % content) + lines.append('%s%s,' % (indent, content)) elif type == 'string': - _GenerateString(content, lines) + _GenerateString(content, lines, indent) elif type == 'string16': - _GenerateString16(content, lines) + _GenerateString16(content, lines, indent) elif type == 'array': - _GenerateArray(element_name, field_info, content, lines) + _GenerateArray(element_name, field_info, content, lines, indent, + field_name_count) + elif type == 'struct': + _GenerateStruct(element_name, field_info, content, lines, indent, + field_name_count) else: raise RuntimeError('Unknown field type "%s"' % type) -def GenerateElement(type_name, schema, element_name, element): +def GenerateElement(type_name, schema, element_name, element, field_name_count): """Generate the static structure initializer for one element. """ lines = []; @@ -102,11 +136,12 @@ def GenerateElement(type_name, schema, element_name, element): if (content == None and not field_info.get('optional', False)): raise RuntimeError('Mandatory field "%s" omitted in element "%s".' % (field_info['field'], element_name)) - GenerateFieldContent(element_name, field_info, content, lines) + GenerateFieldContent(element_name, field_info, content, lines, ' ', + field_name_count) lines.append('};') return '\n'.join(lines) -def GenerateElements(type_name, schema, description): +def GenerateElements(type_name, schema, description, field_name_count={}): """Generate the static structure initializer for all the elements in the description['elements'] dictionary, as well as for any variables in description['int_variables']. @@ -117,6 +152,7 @@ def GenerateElements(type_name, schema, description): result.append('') for element_name, element in description.get('elements', {}).items(): - result.append(GenerateElement(type_name, schema, element_name, element)) + result.append(GenerateElement(type_name, schema, element_name, element, + field_name_count)) result.append('') return '\n'.join(result) diff --git a/tools/json_to_struct/element_generator_test.py b/tools/json_to_struct/element_generator_test.py index 67459a1..373338e 100755 --- a/tools/json_to_struct/element_generator_test.py +++ b/tools/json_to_struct/element_generator_test.py @@ -10,66 +10,72 @@ import unittest class ElementGeneratorTest(unittest.TestCase): def testGenerateIntFieldContent(self): lines = []; - GenerateFieldContent('', {'type': 'int', 'default': 5}, None, lines) + GenerateFieldContent('', {'type': 'int', 'default': 5}, None, lines, ' ', + {}) self.assertEquals([' 5,'], lines) lines = []; - GenerateFieldContent('', {'type': 'int', 'default': 5}, 12, lines) + GenerateFieldContent('', {'type': 'int', 'default': 5}, 12, lines, ' ', {}) self.assertEquals([' 12,'], lines) lines = []; - GenerateFieldContent('', {'type': 'int'}, -3, lines) + GenerateFieldContent('', {'type': 'int'}, -3, lines, ' ', {}) self.assertEquals([' -3,'], lines) def testGenerateStringFieldContent(self): lines = []; GenerateFieldContent('', {'type': 'string', 'default': 'foo_bar'}, None, - lines) + lines, ' ', {}) self.assertEquals([' "foo_bar",'], lines) lines = []; GenerateFieldContent('', {'type': 'string', 'default': 'foo'}, 'bar\n', - lines) + lines, ' ', {}) self.assertEquals([' "bar\\n",'], lines) lines = []; - GenerateFieldContent('', {'type': 'string'}, None, lines) + GenerateFieldContent('', {'type': 'string'}, None, lines, ' ', {}) self.assertEquals([' NULL,'], lines) lines = []; - GenerateFieldContent('', {'type': 'string'}, 'foo', lines) + GenerateFieldContent('', {'type': 'string'}, 'foo', lines, ' ', {}) self.assertEquals([' "foo",'], lines) def testGenerateString16FieldContent(self): lines = []; GenerateFieldContent('', {'type': 'string16', - 'default': u'f\u00d8\u00d81a'}, None, lines) + 'default': u'f\u00d8\u00d81a'}, + None, lines, ' ', {}) self.assertEquals([' L"f\\x00d8" L"\\x00d8" L"1a",'], lines) lines = []; GenerateFieldContent('', {'type': 'string16', 'default': 'foo'}, - u'b\uc3a5r', lines) + u'b\uc3a5r', lines, ' ', {}) self.assertEquals([' L"b\\xc3a5" L"r",'], lines) lines = []; - GenerateFieldContent('', {'type': 'string16'}, None, lines) + GenerateFieldContent('', {'type': 'string16'}, None, lines, ' ', {}) self.assertEquals([' NULL,'], lines) lines = []; - GenerateFieldContent('', {'type': 'string16'}, u'foo\\u1234', lines) + GenerateFieldContent('', {'type': 'string16'}, u'foo\\u1234', lines, ' ', + {}) self.assertEquals([' L"foo\\\\u1234",'], lines) def testGenerateEnumFieldContent(self): lines = []; - GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, None, lines) + GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, None, lines, + ' ', {}) self.assertEquals([' RED,'], lines) lines = []; - GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, 'BLACK', lines) + GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, 'BLACK', lines, + ' ', {}) self.assertEquals([' BLACK,'], lines) lines = []; - GenerateFieldContent('', {'type': 'enum'}, 'BLUE', lines) + GenerateFieldContent('', {'type': 'enum'}, 'BLUE', lines, ' ', {}) self.assertEquals([' BLUE,'], lines) def testGenerateArrayFieldContent(self): lines = ['STRUCT BEGINS']; GenerateFieldContent('test', {'type': 'array', 'contents': {'type': 'int'}}, - None, lines) + None, lines, ' ', {}) self.assertEquals(['STRUCT BEGINS', ' NULL,', ' 0,'], lines) lines = ['STRUCT BEGINS']; GenerateFieldContent('test', {'field': 'my_array', 'type': 'array', - 'contents': {'type': 'int'}}, [3, 4], lines) + 'contents': {'type': 'int'}}, + [3, 4], lines, ' ', {}) self.assertEquals('const int array_test_my_array[] = {\n' + ' 3,\n' + ' 4,\n' + @@ -77,6 +83,17 @@ class ElementGeneratorTest(unittest.TestCase): 'STRUCT BEGINS\n' + ' array_test_my_array,\n' + ' 2,', '\n'.join(lines)) + lines = ['STRUCT BEGINS']; + GenerateFieldContent('test', {'field': 'my_array', 'type': 'array', + 'contents': {'type': 'int'}}, + [3, 4], lines, ' ', {'array_test_my_array': 1}) + self.assertEquals('const int array_test_my_array_1[] = {\n' + + ' 3,\n' + + ' 4,\n' + + '};\n' + + 'STRUCT BEGINS\n' + + ' array_test_my_array_1,\n' + + ' 2,', '\n'.join(lines)) def testGenerateElements(self): schema = [ @@ -85,14 +102,38 @@ class ElementGeneratorTest(unittest.TestCase): {'field': 'f2', 'type': 'enum', 'ctype': 'QuasiBool', 'default': 'MAYBE', 'optional': True}, {'field': 'f3', 'type': 'array', 'contents': {'type': 'string16'}, - 'optional': True} + 'optional': True}, + { + 'field': 'f4', + 'type': 'struct', + 'type_name': 'InnerType', + 'fields': [ + {'field': 'g0', 'type': 'string'} + ], + 'optional': True + }, + { + 'field': 'f5', + 'type': 'array', + 'contents': { + 'type': 'struct', + 'type_name': 'InnerType', + 'fields': [ + {'field': 'a0', 'type': 'string'}, + {'field': 'a1', 'type': 'string'} + ] + }, + 'optional': True + } ] description = { 'int_variables': {'a': -5, 'b': 5}, 'elements': { 'elem0': {'f0': 5, 'f1': 'foo', 'f2': 'SURE'}, 'elem1': {'f2': 'NOWAY', 'f0': -2, 'f1': 'bar'}, - 'elem2': {'f1': 'foo_bar', 'f3': [u'bar', u'foo']} + 'elem2': {'f1': 'foo_bar', 'f3': [u'bar', u'foo']}, + 'elem3': {'f1': 'foo', 'f4': {'g0': 'test'}}, + 'elem4': {'f1': 'foo', 'f5': [{'a0': 'test0', 'a1': 'test1'}]}, } } @@ -103,30 +144,67 @@ class ElementGeneratorTest(unittest.TestCase): 'b': 'const int b = 5;\n', } elements_expected = { - 'elem0': 'const MyType elem0 = {\n' + - ' 5,\n' + - ' "foo",\n' + - ' SURE,\n' + - ' NULL,\n' + + 'elem0': 'const MyType elem0 = {\n' + ' 5,\n' + ' "foo",\n' + ' SURE,\n' + ' NULL,\n' + ' 0,\n' + ' {0},\n' + ' NULL,\n' ' 0,\n' '};\n', - 'elem1': 'const MyType elem1 = {\n' + - ' -2,\n' + - ' "bar",\n' + - ' NOWAY,\n' + - ' NULL,\n' + + 'elem1': 'const MyType elem1 = {\n' + ' -2,\n' + ' "bar",\n' + ' NOWAY,\n' + ' NULL,\n' + ' 0,\n' + ' {0},\n' + ' NULL,\n' ' 0,\n' '};\n', - 'elem2': 'const wchar_t* const array_elem2_f3[] = {\n' + - ' L"bar",\n' + - ' L"foo",\n' + - '};\n' + - 'const MyType elem2 = {\n' + - ' 1000,\n' + - ' "foo_bar",\n' + - ' MAYBE,\n' + - ' array_elem2_f3,\n' + + 'elem2': 'const wchar_t* const array_elem2_f3[] = {\n' + ' L"bar",\n' + ' L"foo",\n' + '};\n' + 'const MyType elem2 = {\n' + ' 1000,\n' + ' "foo_bar",\n' + ' MAYBE,\n' + ' array_elem2_f3,\n' ' 2,\n' + ' {0},\n' + ' NULL,\n' + ' 0,\n' + '};\n', + 'elem3': 'const MyType elem3 = {\n' + ' 1000,\n' + ' "foo",\n' + ' MAYBE,\n' + ' NULL,\n' + ' 0,\n' + ' {\n' + ' "test",\n' + ' },\n' + ' NULL,\n' + ' 0,\n' + '};\n', + 'elem4': 'const InnerType array_elem4_f5[] = {\n' + ' {\n' + ' "test0",\n' + ' "test1",\n' + ' },\n' + '};\n' + 'const MyType elem4 = {\n' + ' 1000,\n' + ' "foo",\n' + ' MAYBE,\n' + ' NULL,\n' + ' 0,\n' + ' {0},\n' + ' array_elem4_f5,\n' + ' 1,\n' '};\n' } expected = '' diff --git a/tools/json_to_struct/json_to_struct.py b/tools/json_to_struct/json_to_struct.py index 2e9c83c7..726cec9 100755 --- a/tools/json_to_struct/json_to_struct.py +++ b/tools/json_to_struct/json_to_struct.py @@ -12,7 +12,7 @@ # "schema": [ // Fields of the generated structure. # { # "field": "my_enum_field", -# "type": "enum", // Either: int, string, string16, enum, array. +# "type": "enum", // Either: int, string, string16, enum, array, struct. # "default": "RED", // Optional. Cannot be used for array. # "ctype": "Color" // Only for enum, specify the C type. # }, @@ -23,6 +23,15 @@ # "type": "int" // Either: int, string, string16, enum, array. # } # }, +# { +# "field": "my_struct_field", +# "type_name": "PointStuct", +# "type": "struct", +# "fields": [ +# {"field": "x", "type": "int"}, +# {"field": "y", "type": "int"} +# ] +# }, # ... # ] # } @@ -39,6 +48,7 @@ # "my_string_field": "foo bar", # "my_enum_field": "BLACK", # "my_int_array_field": [ 1, 2, 3, 5, 7 ], +# "my_struct_field": {"x": 1, "y": 2} # }, # "my_other_const_variable": { # ... @@ -119,7 +129,7 @@ def _GenerateH(basepath, fileroot, head, namespace, schema, description): schema['type_name'], schema['schema'])) f.write('\n') - for var_name, value in description.get('int_variables', []).items(): + for var_name, value in description.get('int_variables', {}).items(): f.write('extern const int %s;\n' % var_name) f.write('\n') diff --git a/tools/json_to_struct/struct_generator.py b/tools/json_to_struct/struct_generator.py index 501cb57..5849d82 100644 --- a/tools/json_to_struct/struct_generator.py +++ b/tools/json_to_struct/struct_generator.py @@ -28,6 +28,8 @@ def GenerateField(field_info): return 'const %s %s' % (field_info['ctype'], field) elif type == 'array': return _GenerateArrayField(field_info) + elif type == 'struct': + return 'const %s %s' % (field_info['type_name'], field) else: raise RuntimeError('Unknown field type "%s"' % type) @@ -38,6 +40,14 @@ def GenerateStruct(type_name, schema): lines = []; lines.append('struct %s {' % type_name) for field_info in schema: + if field_info['type'] == 'struct': + lines.insert(0, GenerateStruct(field_info['type_name'], + field_info['fields'])) + elif (field_info['type'] == 'array' + and field_info['contents']['type'] == 'struct'): + contents = field_info['contents'] + lines.insert(0, GenerateStruct(contents['type_name'], + contents['fields'])) lines.append(' ' + GenerateField(field_info) + ';') lines.append('};'); return '\n'.join(lines) + '\n'; diff --git a/tools/json_to_struct/struct_generator_test.py b/tools/json_to_struct/struct_generator_test.py index 8566c33..bff5db7 100755 --- a/tools/json_to_struct/struct_generator_test.py +++ b/tools/json_to_struct/struct_generator_test.py @@ -54,5 +54,32 @@ class StructGeneratorTest(unittest.TestCase): '};\n') self.assertEquals(struct, GenerateStruct('MyTypeName', schema)) + def testGenerateArrayOfStruct(self): + schema = [ + { + 'type': 'array', + 'field': 'bar_bar', + 'contents': { + 'type': 'struct', + 'type_name': 'InnerTypeName', + 'fields': [ + {'type': 'string', 'field': 'key'}, + {'type': 'string', 'field': 'value'}, + ] + } + } + ] + struct = ( + 'struct InnerTypeName {\n' + ' const char* const key;\n' + ' const char* const value;\n' + '};\n' + '\n' + 'struct MyTypeName {\n' + ' const InnerTypeName * bar_bar;\n' + ' const size_t bar_bar_size;\n' + '};\n') + self.assertEquals(struct, GenerateStruct('MyTypeName', schema)) + if __name__ == '__main__': unittest.main() |