Final step of the java_cpp_template -> java_cpp_enum migration.
This CL migrates the remaining gyp/gn rules away from the java_cpp_template rule. BUG=405532 Review URL: https://codereview.chromium.org/659493003 Cr-Original-Commit-Position: refs/heads/master@{#300881} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: dfdc7fb2bcde7ea4a9458967fdc5f7fa15abb3fa
This commit is contained in:
Родитель
5250a3f2f2
Коммит
c43826dafd
|
@ -14,17 +14,23 @@ import sys
|
|||
from util import build_utils
|
||||
|
||||
class EnumDefinition(object):
|
||||
def __init__(self, class_name=None, class_package=None, entries=None):
|
||||
self.class_name = class_name
|
||||
self.class_package = class_package
|
||||
def __init__(self, original_enum_name=None, class_name_override=None,
|
||||
enum_package=None, entries=None):
|
||||
self.original_enum_name = original_enum_name
|
||||
self.class_name_override = class_name_override
|
||||
self.enum_package = enum_package
|
||||
self.entries = collections.OrderedDict(entries or [])
|
||||
self.prefix_to_strip = ''
|
||||
self.prefix_to_strip = None
|
||||
|
||||
def AppendEntry(self, key, value):
|
||||
if key in self.entries:
|
||||
raise Exception('Multiple definitions of key %s found.' % key)
|
||||
self.entries[key] = value
|
||||
|
||||
@property
|
||||
def class_name(self):
|
||||
return self.class_name_override or self.original_enum_name
|
||||
|
||||
def Finalize(self):
|
||||
self._Validate()
|
||||
self._AssignEntryIndices()
|
||||
|
@ -32,7 +38,7 @@ class EnumDefinition(object):
|
|||
|
||||
def _Validate(self):
|
||||
assert self.class_name
|
||||
assert self.class_package
|
||||
assert self.enum_package
|
||||
assert self.entries
|
||||
|
||||
def _AssignEntryIndices(self):
|
||||
|
@ -54,23 +60,59 @@ class EnumDefinition(object):
|
|||
|
||||
|
||||
def _StripPrefix(self):
|
||||
if not self.prefix_to_strip:
|
||||
prefix_to_strip = re.sub('(?!^)([A-Z]+)', r'_\1', self.class_name).upper()
|
||||
prefix_to_strip = self.prefix_to_strip
|
||||
if not prefix_to_strip:
|
||||
prefix_to_strip = self.original_enum_name
|
||||
prefix_to_strip = re.sub('(?!^)([A-Z]+)', r'_\1', prefix_to_strip).upper()
|
||||
prefix_to_strip += '_'
|
||||
if not all([w.startswith(prefix_to_strip) for w in self.entries.keys()]):
|
||||
prefix_to_strip = ''
|
||||
else:
|
||||
prefix_to_strip = self.prefix_to_strip
|
||||
entries = ((k.replace(prefix_to_strip, '', 1), v) for (k, v) in
|
||||
self.entries.iteritems())
|
||||
self.entries = collections.OrderedDict(entries)
|
||||
|
||||
entries = collections.OrderedDict()
|
||||
for (k, v) in self.entries.iteritems():
|
||||
stripped_key = k.replace(prefix_to_strip, '', 1)
|
||||
if isinstance(v, basestring):
|
||||
stripped_value = v.replace(prefix_to_strip, '', 1)
|
||||
else:
|
||||
stripped_value = v
|
||||
entries[stripped_key] = stripped_value
|
||||
|
||||
self.entries = entries
|
||||
|
||||
class DirectiveSet(object):
|
||||
class_name_override_key = 'CLASS_NAME_OVERRIDE'
|
||||
enum_package_key = 'ENUM_PACKAGE'
|
||||
prefix_to_strip_key = 'PREFIX_TO_STRIP'
|
||||
|
||||
known_keys = [class_name_override_key, enum_package_key, prefix_to_strip_key]
|
||||
|
||||
def __init__(self):
|
||||
self._directives = {}
|
||||
|
||||
def Update(self, key, value):
|
||||
if key not in DirectiveSet.known_keys:
|
||||
raise Exception("Unknown directive: " + key)
|
||||
self._directives[key] = value
|
||||
|
||||
@property
|
||||
def empty(self):
|
||||
return len(self._directives) == 0
|
||||
|
||||
def UpdateDefinition(self, definition):
|
||||
definition.class_name_override = self._directives.get(
|
||||
DirectiveSet.class_name_override_key, '')
|
||||
definition.enum_package = self._directives.get(
|
||||
DirectiveSet.enum_package_key)
|
||||
definition.prefix_to_strip = self._directives.get(
|
||||
DirectiveSet.prefix_to_strip_key)
|
||||
|
||||
|
||||
class HeaderParser(object):
|
||||
single_line_comment_re = re.compile(r'\s*//')
|
||||
multi_line_comment_start_re = re.compile(r'\s*/\*')
|
||||
enum_start_re = re.compile(r'^\s*enum\s+(\w+)\s+{\s*$')
|
||||
enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,\n]+))?,?')
|
||||
enum_end_re = re.compile(r'^\s*}\s*;\s*$')
|
||||
enum_end_re = re.compile(r'^\s*}\s*;\.*$')
|
||||
generator_directive_re = re.compile(
|
||||
r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$')
|
||||
|
||||
|
@ -79,7 +121,7 @@ class HeaderParser(object):
|
|||
self._enum_definitions = []
|
||||
self._in_enum = False
|
||||
self._current_definition = None
|
||||
self._generator_directives = {}
|
||||
self._generator_directives = DirectiveSet()
|
||||
|
||||
def ParseDefinitions(self):
|
||||
for line in self._lines:
|
||||
|
@ -109,31 +151,23 @@ class HeaderParser(object):
|
|||
enum_value = enum_entry.groups()[2]
|
||||
self._current_definition.AppendEntry(enum_key, enum_value)
|
||||
|
||||
def _GetCurrentEnumPackageName(self):
|
||||
return self._generator_directives.get('ENUM_PACKAGE')
|
||||
|
||||
def _GetCurrentEnumPrefixToStrip(self):
|
||||
return self._generator_directives.get('PREFIX_TO_STRIP', '')
|
||||
|
||||
def _ApplyGeneratorDirectives(self):
|
||||
current_definition = self._current_definition
|
||||
current_definition.class_package = self._GetCurrentEnumPackageName()
|
||||
current_definition.prefix_to_strip = self._GetCurrentEnumPrefixToStrip()
|
||||
self._generator_directives = {}
|
||||
self._generator_directives.UpdateDefinition(self._current_definition)
|
||||
self._generator_directives = DirectiveSet()
|
||||
|
||||
def _ParseRegularLine(self, line):
|
||||
enum_start = HeaderParser.enum_start_re.match(line)
|
||||
generator_directive = HeaderParser.generator_directive_re.match(line)
|
||||
if enum_start:
|
||||
if not self._GetCurrentEnumPackageName():
|
||||
if self._generator_directives.empty:
|
||||
return
|
||||
self._current_definition = EnumDefinition()
|
||||
self._current_definition.class_name = enum_start.groups()[0]
|
||||
self._current_definition = EnumDefinition(
|
||||
original_enum_name=enum_start.groups()[0])
|
||||
self._in_enum = True
|
||||
elif generator_directive:
|
||||
directive_name = generator_directive.groups()[0]
|
||||
directive_value = generator_directive.groups()[1]
|
||||
self._generator_directives[directive_name] = directive_value
|
||||
self._generator_directives.Update(directive_name, directive_value)
|
||||
|
||||
|
||||
def GetScriptName():
|
||||
|
@ -147,7 +181,7 @@ def DoGenerate(options, source_paths):
|
|||
for source_path in source_paths:
|
||||
enum_definitions = DoParseHeaderFile(source_path)
|
||||
for enum_definition in enum_definitions:
|
||||
package_path = enum_definition.class_package.replace('.', os.path.sep)
|
||||
package_path = enum_definition.enum_package.replace('.', os.path.sep)
|
||||
file_name = enum_definition.class_name + '.java'
|
||||
output_path = os.path.join(options.output_dir, package_path, file_name)
|
||||
output_paths.append(output_path)
|
||||
|
@ -193,7 +227,7 @@ ${ENUM_ENTRIES}
|
|||
values = {
|
||||
'CLASS_NAME': enum_definition.class_name,
|
||||
'ENUM_ENTRIES': enum_entries_string,
|
||||
'PACKAGE': enum_definition.class_package,
|
||||
'PACKAGE': enum_definition.enum_package,
|
||||
'SCRIPT_NAME': GetScriptName(),
|
||||
'SOURCE_PATH': source_path,
|
||||
}
|
||||
|
|
|
@ -9,13 +9,20 @@ This test suite containss various tests for the C++ -> Java enum generator.
|
|||
"""
|
||||
|
||||
import collections
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from java_cpp_enum import EnumDefinition, GenerateOutput, HeaderParser
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), "gyp"))
|
||||
from util import build_utils
|
||||
|
||||
class TestPreprocess(unittest.TestCase):
|
||||
def testOutput(self):
|
||||
definition = EnumDefinition(class_name='ClassName',
|
||||
class_package='some.package',
|
||||
definition = EnumDefinition(original_enum_name='ClassName',
|
||||
enum_package='some.package',
|
||||
entries=[('E1', 1), ('E2', '2 << 2')])
|
||||
output = GenerateOutput('path/to/file', definition)
|
||||
expected = """
|
||||
|
@ -49,11 +56,54 @@ public class ClassName {
|
|||
self.assertEqual(1, len(definitions))
|
||||
definition = definitions[0]
|
||||
self.assertEqual('EnumName', definition.class_name)
|
||||
self.assertEqual('test.namespace', definition.class_package)
|
||||
self.assertEqual('test.namespace', definition.enum_package)
|
||||
self.assertEqual(collections.OrderedDict([('VALUE_ZERO', 0),
|
||||
('VALUE_ONE', 1)]),
|
||||
definition.entries)
|
||||
|
||||
def testParseBitShifts(self):
|
||||
test_data = """
|
||||
// GENERATED_JAVA_ENUM_PACKAGE: test.namespace
|
||||
enum EnumName {
|
||||
VALUE_ZERO = 1 << 0,
|
||||
VALUE_ONE = 1 << 1,
|
||||
};
|
||||
""".split('\n')
|
||||
definitions = HeaderParser(test_data).ParseDefinitions()
|
||||
self.assertEqual(1, len(definitions))
|
||||
definition = definitions[0]
|
||||
self.assertEqual('EnumName', definition.class_name)
|
||||
self.assertEqual('test.namespace', definition.enum_package)
|
||||
self.assertEqual(collections.OrderedDict([('VALUE_ZERO', '1 << 0'),
|
||||
('VALUE_ONE', '1 << 1')]),
|
||||
definition.entries)
|
||||
|
||||
def testParseClassNameOverride(self):
|
||||
test_data = """
|
||||
// GENERATED_JAVA_ENUM_PACKAGE: test.namespace
|
||||
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: OverrideName
|
||||
enum EnumName {
|
||||
FOO
|
||||
};
|
||||
|
||||
// GENERATED_JAVA_ENUM_PACKAGE: test.namespace
|
||||
// GENERATED_JAVA_CLASS_NAME_OVERRIDE: OtherOverride
|
||||
enum PrefixTest {
|
||||
PREFIX_TEST_A,
|
||||
PREFIX_TEST_B,
|
||||
};
|
||||
""".split('\n')
|
||||
definitions = HeaderParser(test_data).ParseDefinitions()
|
||||
self.assertEqual(2, len(definitions))
|
||||
definition = definitions[0]
|
||||
self.assertEqual('OverrideName', definition.class_name)
|
||||
|
||||
definition = definitions[1]
|
||||
self.assertEqual('OtherOverride', definition.class_name)
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 1)]),
|
||||
definition.entries)
|
||||
|
||||
def testParseTwoEnums(self):
|
||||
test_data = """
|
||||
// GENERATED_JAVA_ENUM_PACKAGE: test.namespace
|
||||
|
@ -78,20 +128,30 @@ public class ClassName {
|
|||
self.assertEqual(2, len(definitions))
|
||||
definition = definitions[0]
|
||||
self.assertEqual('EnumOne', definition.class_name)
|
||||
self.assertEqual('test.namespace', definition.class_package)
|
||||
self.assertEqual('test.namespace', definition.enum_package)
|
||||
self.assertEqual(collections.OrderedDict([('A', '1'),
|
||||
('B', 'A')]),
|
||||
definition.entries)
|
||||
|
||||
definition = definitions[1]
|
||||
self.assertEqual('EnumTwo', definition.class_name)
|
||||
self.assertEqual('other.package', definition.class_package)
|
||||
self.assertEqual('other.package', definition.enum_package)
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 1)]),
|
||||
definition.entries)
|
||||
|
||||
def testParseThrowsOnUnknownDirective(self):
|
||||
test_data = """
|
||||
// GENERATED_JAVA_UNKNOWN: Value
|
||||
enum EnumName {
|
||||
VALUE_ONE,
|
||||
};
|
||||
""".split('\n')
|
||||
with self.assertRaises(Exception):
|
||||
HeaderParser(test_data).ParseDefinitions()
|
||||
|
||||
def testEnumValueAssignmentNoneDefined(self):
|
||||
definition = EnumDefinition('c', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', None)
|
||||
definition.AppendEntry('C', None)
|
||||
|
@ -102,7 +162,7 @@ public class ClassName {
|
|||
definition.entries)
|
||||
|
||||
def testEnumValueAssignmentAllDefined(self):
|
||||
definition = EnumDefinition('c', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', '1')
|
||||
definition.AppendEntry('B', '2')
|
||||
definition.AppendEntry('C', '3')
|
||||
|
@ -113,7 +173,7 @@ public class ClassName {
|
|||
definition.entries)
|
||||
|
||||
def testEnumValueAssignmentReferences(self):
|
||||
definition = EnumDefinition('c', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', 'A')
|
||||
definition.AppendEntry('C', None)
|
||||
|
@ -125,39 +185,85 @@ public class ClassName {
|
|||
('D', 1)]),
|
||||
definition.entries)
|
||||
|
||||
def testEnumValueAssignmentRaises(self):
|
||||
definition = EnumDefinition('c', 'p', [])
|
||||
def testEnumValueAssignmentSet(self):
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', '1')
|
||||
definition.AppendEntry('B', '2')
|
||||
definition.AppendEntry('C', None)
|
||||
definition.Finalize()
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 2),
|
||||
('C', 3)]),
|
||||
definition.entries)
|
||||
|
||||
def testEnumValueAssignmentSetReferences(self):
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', 'A')
|
||||
definition.AppendEntry('C', 'B')
|
||||
definition.AppendEntry('D', None)
|
||||
definition.Finalize()
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 0),
|
||||
('C', 0),
|
||||
('D', 1)]),
|
||||
definition.entries)
|
||||
|
||||
def testEnumValueAssignmentRaises(self):
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', 'foo')
|
||||
definition.AppendEntry('C', None)
|
||||
with self.assertRaises(Exception):
|
||||
definition.Finalize()
|
||||
|
||||
def testExplicitPrefixStripping(self):
|
||||
definition = EnumDefinition('c', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='c', enum_package='p')
|
||||
definition.AppendEntry('P_A', None)
|
||||
definition.AppendEntry('B', None)
|
||||
definition.AppendEntry('P_C', None)
|
||||
definition.AppendEntry('P_LAST', 'P_C')
|
||||
definition.prefix_to_strip = 'P_'
|
||||
definition.Finalize()
|
||||
self.assertEqual(['A', 'B', 'C'], definition.entries.keys())
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 1),
|
||||
('C', 2),
|
||||
('LAST', 2)]),
|
||||
definition.entries)
|
||||
|
||||
def testImplicitPrefixStripping(self):
|
||||
definition = EnumDefinition('ClassName', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='ClassName',
|
||||
enum_package='p')
|
||||
definition.AppendEntry('CLASS_NAME_A', None)
|
||||
definition.AppendEntry('CLASS_NAME_B', None)
|
||||
definition.AppendEntry('CLASS_NAME_C', None)
|
||||
definition.AppendEntry('CLASS_NAME_LAST', 'CLASS_NAME_C')
|
||||
definition.Finalize()
|
||||
self.assertEqual(['A', 'B', 'C'], definition.entries.keys())
|
||||
self.assertEqual(collections.OrderedDict([('A', 0),
|
||||
('B', 1),
|
||||
('C', 2),
|
||||
('LAST', 2)]),
|
||||
definition.entries)
|
||||
|
||||
def testImplicitPrefixStrippingRequiresAllConstantsToBePrefixed(self):
|
||||
definition = EnumDefinition('Name', 'p', [])
|
||||
definition = EnumDefinition(original_enum_name='Name',
|
||||
enum_package='p')
|
||||
definition.AppendEntry('A', None)
|
||||
definition.AppendEntry('B', None)
|
||||
definition.AppendEntry('NAME_LAST', None)
|
||||
definition.Finalize()
|
||||
self.assertEqual(['A', 'B', 'NAME_LAST'], definition.entries.keys())
|
||||
|
||||
def main(argv):
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option("--stamp", help="File to touch on success.")
|
||||
options, _ = parser.parse_args(argv)
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestPreprocess)
|
||||
unittest.TextTestRunner(verbosity=0).run(suite)
|
||||
|
||||
if options.stamp:
|
||||
build_utils.Touch(options.stamp)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
main(sys.argv[1:])
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
# to generate Java source files from templates that are processed
|
||||
# through the host C pre-processor.
|
||||
#
|
||||
# NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
|
||||
# rule instead.
|
||||
#
|
||||
# To use this, create a gyp target with the following form:
|
||||
# {
|
||||
# 'target_name': 'android_net_java_constants',
|
||||
|
@ -15,7 +18,7 @@
|
|||
# ],
|
||||
# 'variables': {
|
||||
# 'package_name': 'org/chromium/net',
|
||||
# 'template_deps': ['net/base/certificate_mime_type_list.h'],
|
||||
# 'template_deps': ['base/net_error_list.h'],
|
||||
# },
|
||||
# 'includes': [ '../build/android/java_cpp_template.gypi' ],
|
||||
# },
|
||||
|
|
|
@ -187,6 +187,9 @@ template("generate_jar_jni") {
|
|||
|
||||
# Declare a target for c-preprocessor-generated java files
|
||||
#
|
||||
# NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
|
||||
# rule instead.
|
||||
#
|
||||
# This target generates java files using the host C pre-processor. Each file in
|
||||
# sources will be compiled using the C pre-processor. If include_path is
|
||||
# specified, it will be passed (with --I) to the pre-processor.
|
||||
|
|
|
@ -57,8 +57,7 @@ def print_landmines():
|
|||
print 'blink_resources.grd changed: crbug.com/400860'
|
||||
print 'ninja dependency cycle: crbug.com/408192'
|
||||
if platform() == 'android':
|
||||
print 'Clobber: To delete stale generated .java files.'
|
||||
print 'Delete stale generated .java files again. crbug.com/349592'
|
||||
print 'Delete stale generated .java files yet again. crbug.com/349592'
|
||||
|
||||
|
||||
def main():
|
||||
|
|
Загрузка…
Ссылка в новой задаче