OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/tools/profile_reset/jtl_parser.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/strings/string_util.h" | |
9 #include "base/values.h" | |
10 #include "third_party/re2/re2/re2.h" | |
11 | |
12 namespace { | |
13 | |
14 // RegEx that matches the first line of a text. Will throw away any potential | |
15 // double-slash introduced comments and the potential trailing EOL character. | |
16 // Gracefully handles slashes inside quotes, and even mismatched quotes. See | |
17 // unit tests for details. | |
18 const char kSingleLineWithMaybeCommentsRE[] = | |
19 "((?:\"[^\"]*\"|.)*?)(?://.*)?(?:\n|$)"; | |
battre
2013/09/27 15:00:01
How about splitting this into something like
"
engedy
2013/10/01 10:48:10
Done.
| |
20 | |
21 // Separator to terminate a sentence. | |
22 const char kEndOfSentenceSeparator[] = ";"; | |
23 | |
24 // Separator to continue a sentence with another operation. | |
25 const char kContinueSentenceSeparator[] = "/"; | |
26 | |
27 // The 'true' Boolean keyword. | |
28 const char kTrueKeyword[] = "true"; | |
29 | |
30 // The 'false' Boolean keyword. | |
31 const char kFalseKeyword[] = "false"; | |
32 | |
33 // RegEx that matches and captures one argument, which is either a double-quote | |
34 // enclosed string, or a Boolean value. Will throw away a trailing comma. | |
35 const char kSingleArgumentRE[] = "(?:(?:(?:\"([^\"]*)\")|(true|false))(?:,|$))"; | |
36 | |
37 // RegEx-es that, when concatenated, will match a single operation, and capture | |
38 // the: operation name, the optional arguments, and the separator that follows. | |
39 const char kOperationNameRE[] = "([[:word:]]+)"; | |
40 const char kMaybeArgumentListRE[] = "(?:\\(((?:\"[^\"]*\"|[^\")])*)\\))?"; | |
41 const char kOperationSeparatorRE[] = "(;|/)"; | |
42 | |
43 } // namespace | |
44 | |
45 struct JtlParser::ParsingState { | |
46 explicit ParsingState(const std::string& compacted_source) | |
47 : single_operation_regex(std::string(kOperationNameRE) + | |
48 kMaybeArgumentListRE + | |
49 kOperationSeparatorRE), | |
50 single_argument_regex(kSingleArgumentRE), | |
51 remaining_compacted_source(compacted_source), | |
52 last_line_number(0) {} | |
53 | |
54 RE2 single_operation_regex; | |
55 RE2 single_argument_regex; | |
56 re2::StringPiece remaining_compacted_source; | |
57 re2::StringPiece last_context; | |
58 size_t last_line_number; | |
59 }; | |
60 | |
61 JtlParser::JtlParser(const std::string& compacted_source, | |
62 const std::vector<size_t>& newline_indices) | |
63 : compacted_source_(compacted_source), | |
64 newline_indices_(newline_indices), | |
65 state_(new ParsingState(compacted_source)) {} | |
66 | |
67 JtlParser::~JtlParser() {} | |
68 | |
69 JtlParser* JtlParser::Create(const std::string& source_code) { | |
70 std::string compacted_source; | |
71 std::vector<size_t> newline_indices; | |
72 RemoveCommentsAndAllWhitespace( | |
73 source_code, &compacted_source, &newline_indices); | |
74 return new JtlParser(compacted_source, newline_indices); | |
75 } | |
76 | |
77 void JtlParser::RemoveCommentsAndAllWhitespace( | |
78 const std::string& verbose_text, | |
79 std::string* compacted_text, | |
80 std::vector<size_t>* newline_indices) { | |
81 DCHECK(compacted_text); | |
82 DCHECK(newline_indices); | |
83 std::string line_without_comments; | |
84 RE2 single_line_regex(kSingleLineWithMaybeCommentsRE); | |
85 re2::StringPiece verbose_text_piece(verbose_text); | |
86 while (!verbose_text_piece.empty() && | |
87 RE2::Consume( | |
88 &verbose_text_piece, single_line_regex, &line_without_comments)) { | |
89 std::string compacted_line; | |
90 RemoveChars(line_without_comments, kWhitespaceASCII, &compacted_line); | |
91 *compacted_text += compacted_line; | |
92 newline_indices->push_back(compacted_text->size()); | |
93 } | |
94 DCHECK(verbose_text_piece.empty()); | |
95 } | |
96 | |
97 bool JtlParser::HasNextOperation() { | |
98 return !state_->remaining_compacted_source.empty(); | |
99 } | |
100 | |
101 bool JtlParser::ParseNextOperation(std::string* name, | |
102 base::ListValue* argument_list, | |
103 bool* ends_sentence) { | |
104 DCHECK(name); | |
105 DCHECK(argument_list); | |
106 DCHECK(ends_sentence); | |
107 | |
108 state_->last_context = state_->remaining_compacted_source; | |
109 state_->last_line_number = GetOriginalLineNumber( | |
110 compacted_source_.size() - state_->remaining_compacted_source.length()); | |
111 | |
112 std::string arguments, separator; | |
113 if (!RE2::Consume(&state_->remaining_compacted_source, | |
114 state_->single_operation_regex, | |
115 name, | |
116 &arguments, | |
117 &separator)) | |
118 return false; | |
119 | |
120 *ends_sentence = (separator == kEndOfSentenceSeparator); | |
121 state_->last_context.remove_suffix(state_->remaining_compacted_source.size()); | |
122 | |
123 re2::StringPiece arguments_piece(arguments); | |
124 std::string string_value, boolean_value; | |
125 while (!arguments_piece.empty()) { | |
126 if (!RE2::Consume(&arguments_piece, | |
127 state_->single_argument_regex, | |
128 &string_value, | |
129 &boolean_value)) | |
130 return false; | |
131 | |
132 if (!boolean_value.empty()) | |
133 argument_list->Append( | |
134 new base::FundamentalValue(boolean_value == kTrueKeyword)); | |
135 else // |string_value| might be empty for an empty string | |
136 argument_list->Append(new StringValue(string_value)); | |
137 } | |
138 return true; | |
139 } | |
140 | |
141 size_t JtlParser::GetOriginalLineNumber(size_t compacted_index) const { | |
142 return static_cast<size_t>(std::upper_bound(newline_indices_.begin(), | |
143 newline_indices_.end(), | |
144 compacted_index) - | |
145 newline_indices_.begin()); | |
146 } | |
147 | |
148 size_t JtlParser::last_line_number() const { return state_->last_line_number; } | |
149 | |
150 std::string JtlParser::last_context() const { | |
151 return state_->last_context.ToString(); | |
152 } | |
OLD | NEW |