Commit 622ae94f authored by Nate Fischer's avatar Nate Fischer Committed by Commit Bot

Android: support escapes in multiline strings definitions

This adds support for escape characters in multiline strings definitions
(where the variable name and the string literal are on different lines,
not for string literals which span multiple lines). This also simplifies
STRING_RE because it no longer needs to contain a regex for the string
literal.

This also adds tests for empty string. This hardens the regex to avoid
mistaking multiple string literals (which is often used to split a
string literal across multiple lines) with a complete string expression.

This also removes _ToUpper and _GetClassName because these are unused by
this class.

Fixed: 1129591
Test: vpython build/android/gyp/java_cpp_strings_tests.py
Change-Id: Ib4b6dcc2bbe70081ebaaa3552b4cb6d36dc0ffe9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2417488Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Commit-Queue: Nate Fischer <ntfschr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808180}
parent ba5a0921
...@@ -14,18 +14,6 @@ from util import build_utils ...@@ -14,18 +14,6 @@ from util import build_utils
from util import java_cpp_utils from util import java_cpp_utils
def _ToUpper(match):
return match.group(1).upper()
def _GetClassName(source_path):
name = os.path.basename(os.path.abspath(source_path))
(name, _) = os.path.splitext(name)
name = re.sub(r'_([a-z])', _ToUpper, name)
name = re.sub(r'^(.)', _ToUpper, name)
return name
class _String(object): class _String(object):
def __init__(self, name, value, comments): def __init__(self, name, value, comments):
...@@ -61,8 +49,8 @@ def ParseTemplateFile(lines): ...@@ -61,8 +49,8 @@ def ParseTemplateFile(lines):
# in the file to be parsed. # in the file to be parsed.
class StringFileParser(object): class StringFileParser(object):
SINGLE_LINE_COMMENT_RE = re.compile(r'\s*(// [^\n]*)') SINGLE_LINE_COMMENT_RE = re.compile(r'\s*(// [^\n]*)')
STRING_RE = re.compile(r'\s*const char k(.*)\[\]\s*=\s*(?:(".*"))?') STRING_RE = re.compile(r'\s*const char k(.*)\[\]\s*=')
VALUE_RE = re.compile(r'\s*("[^"]*")') VALUE_RE = re.compile(r'\s*("(?:\"|[^"])*")\s*;')
def __init__(self, lines, path=''): def __init__(self, lines, path=''):
self._lines = lines self._lines = lines
...@@ -75,6 +63,14 @@ class StringFileParser(object): ...@@ -75,6 +63,14 @@ class StringFileParser(object):
self._current_value = '' self._current_value = ''
self._strings = [] self._strings = []
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): def _Reset(self):
self._current_comments = [] self._current_comments = []
self._current_name = '' self._current_name = ''
...@@ -89,9 +85,9 @@ class StringFileParser(object): ...@@ -89,9 +85,9 @@ class StringFileParser(object):
self._Reset() self._Reset()
def _ParseValue(self, line): def _ParseValue(self, line):
value_line = StringFileParser.VALUE_RE.match(line) current_value = self._ExtractValue(line)
if value_line: if current_value is not None:
self._current_value = value_line.groups()[0] self._current_value = current_value
self._AppendString() self._AppendString()
else: else:
self._Reset() self._Reset()
...@@ -108,11 +104,12 @@ class StringFileParser(object): ...@@ -108,11 +104,12 @@ class StringFileParser(object):
return False return False
def _ParseString(self, line): def _ParseString(self, line):
string_line = StringFileParser.STRING_RE.match(line) current_name = self._ExtractVariable(line)
if string_line: if current_name is not None:
self._current_name = string_line.groups()[0] self._current_name = current_name
if string_line.groups()[1]: current_value = self._ExtractValue(line)
self._current_value = string_line.groups()[1] if current_value is not None:
self._current_value = current_value
self._AppendString() self._AppendString()
else: else:
self._in_string = True self._in_string = True
......
...@@ -46,7 +46,7 @@ const char kAnotherSwitch[] = "another-value"; ...@@ -46,7 +46,7 @@ const char kAnotherSwitch[] = "another-value";
self.assertEqual(2, len(strings[1].comments.split('\n'))) self.assertEqual(2, len(strings[1].comments.split('\n')))
def testStringValues(self): def testStringValues(self):
test_data = """ test_data = r"""
// Single line string constants. // Single line string constants.
const char kAString[] = "a-value"; const char kAString[] = "a-value";
const char kNoComment[] = "no-comment"; const char kNoComment[] = "no-comment";
...@@ -67,13 +67,23 @@ const char kAStringWithAVeryLongNameThatWillHaveToWrap[] = ...@@ -67,13 +67,23 @@ const char kAStringWithAVeryLongNameThatWillHaveToWrap[] =
const char kAStringWithAVeryLongNameThatWillHaveToWrap2[] = const char kAStringWithAVeryLongNameThatWillHaveToWrap2[] =
"a-string-with-a-very-long-name-that-will-have-to-wrap2"; "a-string-with-a-very-long-name-that-will-have-to-wrap2";
// This is erroneous and should be ignored. const char kStringWithEscapes[] = "tab\tquote\"newline\n";
const char kStringWithEscapes2[] =
"tab\tquote\"newline\n";
const char kEmptyString[] = "";
// These are valid C++ but not currently supported by the script.
const char kInvalidLineBreak[] = const char kInvalidLineBreak[] =
"invalid-line-break"; "invalid-line-break";
const char kConcatenateMultipleStringLiterals[] =
"first line"
"second line";
""".split('\n') """.split('\n')
strings = java_cpp_strings.StringFileParser(test_data).Parse() strings = java_cpp_strings.StringFileParser(test_data).Parse()
self.assertEqual(6, len(strings)) self.assertEqual(9, len(strings))
self.assertEqual('A_STRING', strings[0].name) self.assertEqual('A_STRING', strings[0].name)
self.assertEqual('"a-value"', strings[0].value) self.assertEqual('"a-value"', strings[0].value)
self.assertEqual('NO_COMMENT', strings[1].name) self.assertEqual('NO_COMMENT', strings[1].name)
...@@ -90,6 +100,12 @@ const char kInvalidLineBreak[] = ...@@ -90,6 +100,12 @@ const char kInvalidLineBreak[] =
strings[5].name) strings[5].name)
self.assertEqual('"a-string-with-a-very-long-name-that-will-have-to-wrap2"', self.assertEqual('"a-string-with-a-very-long-name-that-will-have-to-wrap2"',
strings[5].value) strings[5].value)
self.assertEqual('STRING_WITH_ESCAPES', strings[6].name)
self.assertEqual(r'"tab\tquote\"newline\n"', strings[6].value)
self.assertEqual('STRING_WITH_ESCAPES2', strings[7].name)
self.assertEqual(r'"tab\tquote\"newline\n"', strings[7].value)
self.assertEqual('EMPTY_STRING', strings[8].name)
self.assertEqual('""', strings[8].value)
def testTreatWebViewLikeOneWord(self): def testTreatWebViewLikeOneWord(self):
test_data = """ test_data = """
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment