blob: b5c26c72f69a8cdd043e4f1b44ebc5e21f5c554a [file] [log] [blame]
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import class_generator
_INDENT = ' '
def _GenerateString(content, 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:
return indent + 'null,'
else:
# json.dumps quotes the string and escape characters as required.
return indent + '%s,' % json.dumps(content)
def _GenerateArrayVariableName(element_name, field_name, field_name_count):
"""Generates a unique variable name for an array variable.
"""
var = '%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, indent, field_name_count):
"""Generates an array created inline in a constructor call. If content is
not specified, null is used.
"""
if content is None:
return indent + 'null,'
lines = []
array_field = class_generator.GenerateField(field_info['contents'])
array_type = array_field[:array_field.find(' ')]
lines.append(indent + 'new %s[]{' % array_type)
for subcontent in content:
lines.append(
_GenerateFieldContent(element_name, field_info['contents'], subcontent,
indent + _INDENT, field_name_count))
lines.append(indent + '},')
return '\n'.join(lines)
def _GenerateClass(element_name, field_info, content, indent, field_name_count):
"""Generates a class to be used in a constructor call. If content is not
specified, use null.
"""
if content is None:
return indent + 'null'
lines = []
fields = field_info['fields']
class_name = field_info['type_name']
lines.append(indent + 'new ' + class_name + '(')
for field in fields:
subcontent = content.get(field['field'])
lines.append(
_GenerateFieldContent(element_name, field, subcontent, indent + _INDENT,
field_name_count))
# remove the trailing comma for the last parameter
lines[-1] = lines[-1][:-1]
lines.append(indent + '),')
return '\n'.join(lines)
def _GenerateFieldContent(element_name, field_info, content, indent,
field_name_count):
"""Generate the content of a field to be included in the constructor call. If
the field's content is not specified, uses the default value if one exists.
"""
if content is None:
content = field_info.get('java_default', None)
java_type = field_info['type']
if java_type in ('int', 'class'):
return '%s%s,' % (indent, content)
elif java_type == 'enum':
# TODO(peilinwang) temporarily treat enums as strings. Maybe use a
# different schema? Right now these scripts are only used for generating
# fieldtrial testing configs.
return '%s"%s",' % (indent, content)
elif java_type == 'string':
return _GenerateString(content, indent)
elif java_type == 'string16':
raise RuntimeError('Generating a UTF16 java String is not supported yet.')
elif java_type == 'array':
return _GenerateArray(element_name, field_info, content, indent,
field_name_count)
elif java_type == 'struct':
return _GenerateClass(element_name, field_info, content, indent,
field_name_count)
else:
raise RuntimeError('Unknown field type "%s"' % java_type)
def _GenerateElement(type_name, schema, element_name, element,
field_name_count):
"""Generate the constructor call for one element.
"""
lines = []
lines.append(_INDENT + 'public static final %s %s = ' %
(type_name, element_name))
lines.append(2 * _INDENT + 'new %s(' % (type_name))
for field_info in schema:
content = element.get(field_info['field'], None)
if (content == None and not field_info.get('optional', False)):
raise RuntimeError('Mandatory field "%s" omitted in element "%s".' %
(field_info['field'], element_name))
lines.append(
_GenerateFieldContent(element_name, field_info, content, 2 * _INDENT,
field_name_count))
# remove the trailing comma for the last parameter
lines[-1] = lines[-1][:-1]
lines.append(2 * _INDENT + ');')
return '\n'.join(lines)
def GenerateElements(type_name, schema, description, field_name_count={}):
"""Generate the static initializers for all the elements in the
description['elements'] dictionary, as well as for any variables in
description['int_variables']. All elements in description['elements']
will be generated as a public static final int/class.
"""
result = []
for var_name, value in description.get('int_variables', {}).items():
result.append('public static final int %s = %s;' % (var_name, value))
result.append('')
for element_name, element in description.get('elements', {}).items():
result.append(
_GenerateElement(type_name, schema, element_name, element,
field_name_count))
result.append('')
return '\n'.join(result)