blob: 5180400d6161de628e789ff320295ec97d150d78 [file] [log] [blame]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import re
import sys
def GetScriptName():
return os.path.basename(os.path.abspath(sys.argv[0]))
def GetJavaFilePath(java_package, class_name):
package_path = java_package.replace('.', os.path.sep)
file_name = class_name + '.java'
return os.path.join(package_path, file_name)
def KCamelToShouty(s):
"""Convert |s| from kCamelCase or CamelCase to SHOUTY_CASE.
kFooBar -> FOO_BAR
FooBar -> FOO_BAR
FooBAR9 -> FOO_BAR9
FooBARBaz -> FOO_BAR_BAZ
"""
if not re.match(r'^k?([A-Z][^A-Z]+|[A-Z0-9]+)+$', s):
return s
# Strip the leading k.
s = re.sub(r'^k', '', s)
# Treat "WebView" like one word.
s = re.sub(r'WebView', r'Webview', s)
# Add _ between title words and anything else.
s = re.sub(r'([^_])([A-Z][^A-Z_0-9]+)', r'\1_\2', s)
# Add _ between lower -> upper transitions.
s = re.sub(r'([^A-Z_0-9])([A-Z])', r'\1_\2', s)
return s.upper()
class JavaString(object):
def __init__(self, name, value, comments):
self.name = KCamelToShouty(name)
self.value = value
self.comments = '\n'.join(' ' + x for x in comments)
def Format(self):
return '%s\n public static final String %s = %s;' % (
self.comments, self.name, self.value)
def ParseTemplateFile(lines):
package_re = re.compile(r'^package (.*);')
class_re = re.compile(r'.*class (.*) {')
package = ''
class_name = ''
for line in lines:
package_line = package_re.match(line)
if package_line:
package = package_line.groups()[0]
class_line = class_re.match(line)
if class_line:
class_name = class_line.groups()[0]
break
return package, class_name
# TODO(crbug.com/937282): Work will be needed if we want to annotate specific
# constants in the file to be parsed.
class CppConstantParser(object):
"""Parses C++ constants, retaining their comments.
The Delegate subclass is responsible for matching and extracting the
constant's variable name and value, as well as generating an object to
represent the Java representation of this value.
"""
SINGLE_LINE_COMMENT_RE = re.compile(r'\s*(// [^\n]*)')
class Delegate(object):
def ExtractConstantName(self, line):
"""Extracts a constant's name from line or None if not a match."""
raise NotImplementedError()
def ExtractValue(self, line):
"""Extracts a constant's value from line or None if not a match."""
raise NotImplementedError()
def CreateJavaConstant(self, name, value, comments):
"""Creates an object representing the Java analog of a C++ constant.
CppConstantParser will not interact with the object created by this
method. Instead, it will store this value in a list and return a list of
all objects from the Parse() method. In this way, the caller may define
whatever class suits their need.
Args:
name: the constant's variable name, as extracted by
ExtractConstantName()
value: the constant's value, as extracted by ExtractValue()
comments: the code comments describing this constant
"""
raise NotImplementedError()
def __init__(self, delegate, lines):
self._delegate = delegate
self._lines = lines
self._in_variable = False
self._in_comment = False
self._package = ''
self._current_comments = []
self._current_name = ''
self._current_value = ''
self._constants = []
def _ExtractVariable(self, line):
match = StringFileParser.STRING_RE.match(line)
return match.group(1) if match else None
def _ExtractValue(self, line):
match = StringFileParser.VALUE_RE.search(line)
return match.group(1) if match else None
def _Reset(self):
self._current_comments = []
self._current_name = ''
self._current_value = ''
self._in_variable = False
self._in_comment = False
def _AppendConstant(self):
self._constants.append(
self._delegate.CreateJavaConstant(self._current_name,
self._current_value,
self._current_comments))
self._Reset()
def _ParseValue(self, line):
current_value = self._delegate.ExtractValue(line)
if current_value is not None:
self._current_value = current_value
self._AppendConstant()
else:
self._Reset()
def _ParseComment(self, line):
comment_line = CppConstantParser.SINGLE_LINE_COMMENT_RE.match(line)
if comment_line:
self._current_comments.append(comment_line.groups()[0])
self._in_comment = True
self._in_variable = True
return True
else:
self._in_comment = False
return False
def _ParseVariable(self, line):
current_name = self._delegate.ExtractConstantName(line)
if current_name is not None:
self._current_name = current_name
current_value = self._delegate.ExtractValue(line)
if current_value is not None:
self._current_value = current_value
self._AppendConstant()
else:
self._in_variable = True
return True
else:
self._in_variable = False
return False
def _ParseLine(self, line):
if not self._in_variable:
if not self._ParseVariable(line):
self._ParseComment(line)
return
if self._in_comment:
if self._ParseComment(line):
return
if not self._ParseVariable(line):
self._Reset()
return
if self._in_variable:
self._ParseValue(line)
def Parse(self):
"""Returns a list of objects representing C++ constants.
Each object in the list was created by Delegate.CreateJavaValue().
"""
for line in self._lines:
self._ParseLine(line)
return self._constants