| 21 | namespace testing { |
| 22 | |
| 23 | void Tokenize(std::istream* input, TokenProcessor* processor) { |
| 24 | enum State { kBuildQuotedToken, kBuildToken, kIdle }; |
| 25 | |
| 26 | std::string current_token; |
| 27 | State state = kIdle; |
| 28 | auto start_token = [&](char c) { |
| 29 | state = kBuildToken; |
| 30 | current_token.clear(); |
| 31 | current_token = c; |
| 32 | }; |
| 33 | auto issue_token = [&]() { |
| 34 | state = kIdle; |
| 35 | processor->ConsumeToken(¤t_token); |
| 36 | current_token.clear(); |
| 37 | }; |
| 38 | auto start_quoted_token = [&]() { |
| 39 | state = kBuildQuotedToken; |
| 40 | current_token.clear(); |
| 41 | }; |
| 42 | auto issue_quoted_token = [&]() { |
| 43 | state = kIdle; |
| 44 | processor->ConsumeToken(¤t_token); |
| 45 | current_token.clear(); |
| 46 | }; |
| 47 | auto issue_delim = [&](char d) { |
| 48 | current_token = string(1, d); |
| 49 | processor->ConsumeToken(¤t_token); |
| 50 | current_token.clear(); |
| 51 | }; |
| 52 | auto is_delim = [](char c) { return c == '{' || c == '}' || c == ':'; }; |
| 53 | auto is_quote = [](char c) { return c == '"'; }; |
| 54 | |
| 55 | for (auto it = std::istreambuf_iterator<char>(*input); |
| 56 | it != std::istreambuf_iterator<char>(); ++it) { |
| 57 | switch (state) { |
| 58 | case kIdle: |
| 59 | if (is_delim(*it)) { |
| 60 | issue_delim(*it); |
| 61 | } else if (is_quote(*it)) { |
| 62 | start_quoted_token(); |
| 63 | } else if (!isspace(*it)) { |
| 64 | start_token(*it); |
| 65 | } |
| 66 | break; |
| 67 | case kBuildToken: |
| 68 | if (is_delim(*it)) { |
| 69 | issue_token(); |
| 70 | issue_delim(*it); |
| 71 | } else if (is_quote(*it)) { |
| 72 | issue_token(); |
| 73 | start_quoted_token(); |
| 74 | } else if (isspace(*it)) { |
| 75 | issue_token(); |
| 76 | } else { |
| 77 | current_token += *it; |
| 78 | } |
| 79 | break; |
| 80 | case kBuildQuotedToken: |