blob: e3eb4e0870b73361073857d92f3babfcc48f3a4f [file]
# 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)