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:
mkosiba 2014-10-23 06:56:12 -07:00 коммит произвёл Commit bot
Родитель 5250a3f2f2
Коммит c43826dafd
5 изменённых файлов: 195 добавлений и 50 удалений

Просмотреть файл

@ -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():