/*
* 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 "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