- add sources.
[platform/framework/web/crosswalk.git] / src / base / test / expectations / parser.cc
1 // Copyright (c) 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 "base/test/expectations/parser.h"
6
7 #include "base/strings/string_util.h"
8
9 namespace test_expectations {
10
11 Parser::Parser(Delegate* delegate, const std::string& input)
12     : delegate_(delegate),
13       input_(input),
14       pos_(NULL),
15       end_(NULL),
16       line_number_(0),
17       data_error_(false) {
18 }
19
20 Parser::~Parser() {
21 }
22
23 void Parser::Parse() {
24   pos_ = &input_[0];
25   end_ = pos_ + input_.length();
26
27   line_number_ = 1;
28
29   StateFuncPtr state = &Parser::Start;
30   while (state) {
31     state = (this->*state)();
32   }
33 }
34
35 inline bool Parser::HasNext() {
36   return pos_ < end_;
37 }
38
39 Parser::StateFunc Parser::Start() {
40   // If at the start of a line is whitespace, skip it and arrange to come back
41   // here.
42   if (IsAsciiWhitespace(*pos_))
43     return SkipWhitespaceAndNewLines(&Parser::Start);
44
45   // Handle comments at the start of lines.
46   if (*pos_ == '#')
47     return &Parser::ParseComment;
48
49   // After arranging to come back here from skipping whitespace and comments,
50   // the parser may be at the end of the input.
51   if (pos_ >= end_)
52     return NULL;
53
54   current_ = Expectation();
55   data_error_ = false;
56
57   return &Parser::ParseBugURL;
58 }
59
60 Parser::StateFunc Parser::ParseComment() {
61   if (*pos_ != '#')
62     return SyntaxError("Invalid start of comment");
63
64   do {
65     ++pos_;
66   } while (HasNext() && *pos_ != '\n');
67
68   return &Parser::Start;
69 }
70
71 Parser::StateFunc Parser::ParseBugURL() {
72   return SkipWhitespace(ExtractString(
73       &Parser::BeginModifiers));
74 }
75
76 Parser::StateFunc Parser::BeginModifiers() {
77   if (*pos_ != '[' || !HasNext())
78     return SyntaxError("Expected '[' for start of modifiers");
79
80   ++pos_;
81   return SkipWhitespace(&Parser::InModifiers);
82 }
83
84 Parser::StateFunc Parser::InModifiers() {
85   if (*pos_ == ']')
86     return &Parser::EndModifiers;
87
88   return ExtractString(SkipWhitespace(
89       &Parser::SaveModifier));
90 }
91
92 Parser::StateFunc Parser::SaveModifier() {
93   if (extracted_string_.empty())
94     return SyntaxError("Invalid modifier list");
95
96   Configuration config;
97   if (ConfigurationFromString(extracted_string_, &config)) {
98     if (current_.configuration != CONFIGURATION_UNSPECIFIED)
99       DataError("Cannot use more than one configuration modifier");
100     else
101       current_.configuration = config;
102   } else {
103     Platform platform;
104     if (PlatformFromString(extracted_string_, &platform))
105       current_.platforms.push_back(platform);
106     else
107       DataError("Invalid modifier string");
108   }
109
110   return SkipWhitespace(&Parser::InModifiers);
111 }
112
113 Parser::StateFunc Parser::EndModifiers() {
114  if (*pos_ != ']' || !HasNext())
115     return SyntaxError("Expected ']' for end of modifiers list");
116
117   ++pos_;
118   return SkipWhitespace(&Parser::ParseTestName);
119 }
120
121 Parser::StateFunc Parser::ParseTestName() {
122   return ExtractString(&Parser::SaveTestName);
123 }
124
125 Parser::StateFunc Parser::SaveTestName() {
126   if (extracted_string_.empty())
127     return SyntaxError("Invalid test name");
128
129   current_.test_name = extracted_string_.as_string();
130   return SkipWhitespace(&Parser::ParseExpectation);
131 }
132
133 Parser::StateFunc Parser::ParseExpectation() {
134   if (*pos_ != '=' || !HasNext())
135     return SyntaxError("Expected '=' for expectation result");
136
137   ++pos_;
138   return SkipWhitespace(&Parser::ParseExpectationType);
139 }
140
141 Parser::StateFunc Parser::ParseExpectationType() {
142   return ExtractString(&Parser::SaveExpectationType);
143 }
144
145 Parser::StateFunc Parser::SaveExpectationType() {
146   if (!ResultFromString(extracted_string_, &current_.result))
147     DataError("Unknown expectation type");
148
149   return SkipWhitespace(&Parser::End);
150 }
151
152 Parser::StateFunc Parser::End() {
153   if (!data_error_)
154     delegate_->EmitExpectation(current_);
155
156   if (HasNext())
157     return SkipWhitespaceAndNewLines(&Parser::Start);
158
159   return NULL;
160 }
161
162 Parser::StateFunc Parser::ExtractString(StateFunc success) {
163   const char* start = pos_;
164   while (!IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) {
165     ++pos_;
166     if (*pos_ == '#') {
167       return SyntaxError("Unexpected start of comment");
168     }
169   }
170   extracted_string_ = base::StringPiece(start, pos_ - start);
171   return success;
172 }
173
174 Parser::StateFunc Parser::SkipWhitespace(Parser::StateFunc next) {
175   while ((*pos_ == ' ' || *pos_ == '\t') && HasNext()) {
176     ++pos_;
177   }
178   return next;
179 }
180
181 Parser::StateFunc Parser::SkipWhitespaceAndNewLines(Parser::StateFunc next) {
182   while (IsAsciiWhitespace(*pos_) && HasNext()) {
183     if (*pos_ == '\n') {
184       ++line_number_;
185     }
186     ++pos_;
187   }
188   return next;
189 }
190
191 Parser::StateFunc Parser::SyntaxError(const std::string& message) {
192   delegate_->OnSyntaxError(message);
193   return NULL;
194 }
195
196 void Parser::DataError(const std::string& error) {
197   data_error_ = true;
198   delegate_->OnDataError(error);
199 }
200
201 }  // namespace test_expectations