| /* |
| * Copyright 2017 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SKSL_NFASTATE |
| #define SKSL_NFASTATE |
| |
| #include <string> |
| #include <vector> |
| |
| #include "src/sksl/lex/LexUtil.h" |
| |
| struct NFAState { |
| enum Kind { |
| // represents an accept state - if the NFA ends up in this state, we have successfully |
| // matched the token indicated by fData[0] |
| kAccept_Kind, |
| // matches the single character fChar |
| kChar_Kind, |
| // the regex '.'; matches any char but '\n' |
| kDot_Kind, |
| // a state which serves as a placeholder for the states indicated in fData. When we |
| // transition to this state, we instead transition to all of the fData states. |
| kRemapped_Kind, |
| // contains a list of true/false values in fData. fData[c] tells us whether we accept the |
| // character c. |
| kTable_Kind |
| }; |
| |
| NFAState(Kind kind, std::vector<int> next) |
| : fKind(kind) |
| , fNext(std::move(next)) {} |
| |
| NFAState(char c, std::vector<int> next) |
| : fKind(kChar_Kind) |
| , fChar(c) |
| , fNext(std::move(next)) {} |
| |
| NFAState(std::vector<int> states) |
| : fKind(kRemapped_Kind) |
| , fData(std::move(states)) {} |
| |
| NFAState(bool inverse, std::vector<bool> accepts, std::vector<int> next) |
| : fKind(kTable_Kind) |
| , fInverse(inverse) |
| , fNext(std::move(next)) { |
| for (bool b : accepts) { |
| fData.push_back(b); |
| } |
| } |
| |
| NFAState(int token) |
| : fKind(kAccept_Kind) { |
| fData.push_back(token); |
| } |
| |
| bool accept(char c) const { |
| switch (fKind) { |
| case kAccept_Kind: |
| return false; |
| case kChar_Kind: |
| return c == fChar; |
| case kDot_Kind: |
| return c != '\n'; |
| case kTable_Kind: { |
| bool value; |
| if ((size_t) c < fData.size()) { |
| value = fData[c]; |
| } else { |
| value = false; |
| } |
| return value != fInverse; |
| } |
| default: |
| ABORT("unreachable"); |
| } |
| } |
| |
| std::string description() const { |
| switch (fKind) { |
| case kAccept_Kind: |
| return "Accept(" + std::to_string(fData[0]) + ")"; |
| case kChar_Kind: { |
| std::string result = "Char('" + std::string(1, fChar) + "'"; |
| for (int v : fNext) { |
| result += ", "; |
| result += std::to_string(v); |
| } |
| result += ")"; |
| return result; |
| } |
| case kDot_Kind: { |
| std::string result = "Dot("; |
| const char* separator = ""; |
| for (int v : fNext) { |
| result += separator; |
| result += std::to_string(v); |
| separator = ", "; |
| } |
| result += ")"; |
| return result; |
| } |
| case kRemapped_Kind: { |
| std::string result = "Remapped("; |
| const char* separator = ""; |
| for (int v : fData) { |
| result += separator; |
| result += std::to_string(v); |
| separator = ", "; |
| } |
| result += ")"; |
| return result; |
| } |
| case kTable_Kind: { |
| std::string result = std::string("Table(") + (fInverse ? "true" : "false") + ", ["; |
| const char* separator = ""; |
| for (int v : fData) { |
| result += separator; |
| result += v ? "true" : "false"; |
| separator = ", "; |
| } |
| result += "]"; |
| for (int n : fNext) { |
| result += ", "; |
| result += std::to_string(n); |
| } |
| result += ")"; |
| return result; |
| } |
| default: |
| ABORT("unreachable"); |
| } |
| } |
| |
| Kind fKind; |
| |
| char fChar = 0; |
| |
| bool fInverse = false; |
| |
| std::vector<int> fData; |
| |
| // states we transition to upon a succesful match from this state |
| std::vector<int> fNext; |
| }; |
| |
| #endif |