Return Status instead of bool
This commit is contained in:
133
src/test.cpp
133
src/test.cpp
@@ -420,10 +420,10 @@ struct Parser2 {
|
|||||||
|
|
||||||
// Returns false to reject
|
// Returns false to reject
|
||||||
[[nodiscard]] bool parse() {
|
[[nodiscard]] bool parse() {
|
||||||
if (!push({N_VALUE})) {
|
if (push({N_VALUE}) != S_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return keepGoing(this);
|
return keepGoing(this) == S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser2(Parser2 const &) = delete;
|
Parser2(Parser2 const &) = delete;
|
||||||
@@ -433,6 +433,13 @@ struct Parser2 {
|
|||||||
|
|
||||||
static constexpr int kMaxStackSize = 1 << 10;
|
static constexpr int kMaxStackSize = 1 << 10;
|
||||||
|
|
||||||
|
enum Status {
|
||||||
|
S_OK,
|
||||||
|
S_AGAIN,
|
||||||
|
S_REJECT,
|
||||||
|
S_OVERFLOW,
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Helpers
|
// Helpers
|
||||||
void maybeSkipWs() {
|
void maybeSkipWs() {
|
||||||
@@ -440,21 +447,21 @@ private:
|
|||||||
++buf;
|
++buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool parseLiteral(const char *literal) {
|
Status parseLiteral(const char *literal) {
|
||||||
const int litLen = strlen(literal);
|
const int litLen = strlen(literal);
|
||||||
if (len() < litLen) {
|
if (len() < litLen) {
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
if (memcmp(buf, literal, litLen) == 0) {
|
if (memcmp(buf, literal, litLen) == 0) {
|
||||||
buf += litLen;
|
buf += litLen;
|
||||||
return true;
|
return S_OK;
|
||||||
}
|
}
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
bool parse_number() {
|
Status parse_number() {
|
||||||
char *const bufBefore = buf;
|
char *const bufBefore = buf;
|
||||||
if (len() == 0 || !('0' <= *buf && *buf <= '9' || (*buf == '.'))) {
|
if (len() == 0 || !('0' <= *buf && *buf <= '9' || (*buf == '.'))) {
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
callbacks->on_begin_number(data);
|
callbacks->on_begin_number(data);
|
||||||
++buf;
|
++buf;
|
||||||
@@ -467,28 +474,28 @@ private:
|
|||||||
}
|
}
|
||||||
callbacks->on_number_data(data, bufBefore, buf - bufBefore);
|
callbacks->on_number_data(data, bufBefore, buf - bufBefore);
|
||||||
callbacks->on_end_number(data);
|
callbacks->on_end_number(data);
|
||||||
return true;
|
return S_OK;
|
||||||
}
|
}
|
||||||
bool parse_string() {
|
Status parse_string() {
|
||||||
if (!parseLiteral("\"")) {
|
if (Status s = parseLiteral("\"")) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
callbacks->on_begin_string(data);
|
callbacks->on_begin_string(data);
|
||||||
auto *result = (char *)memchr(buf, '"', len());
|
auto *result = (char *)memchr(buf, '"', len());
|
||||||
if (result == nullptr) {
|
if (result == nullptr) {
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
int stringLen = result - buf;
|
int stringLen = result - buf;
|
||||||
callbacks->on_string_data(data, buf, stringLen);
|
callbacks->on_string_data(data, buf, stringLen);
|
||||||
buf += stringLen;
|
buf += stringLen;
|
||||||
if (!parseLiteral("\"")) {
|
if (Status s = parseLiteral("\"")) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
callbacks->on_end_string(data);
|
callbacks->on_end_string(data);
|
||||||
return true;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*continuation)(Parser2 *);
|
typedef Status (*continuation)(Parser2 *);
|
||||||
|
|
||||||
[[maybe_unused]] void debugPrint() {
|
[[maybe_unused]] void debugPrint() {
|
||||||
for (int i = 0; i < stackPtr - stack; ++i) {
|
for (int i = 0; i < stackPtr - stack; ++i) {
|
||||||
@@ -497,120 +504,122 @@ private:
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool keepGoing(Parser2 *self) {
|
static Status keepGoing(Parser2 *self) {
|
||||||
// self->debugPrint();
|
// self->debugPrint();
|
||||||
if (self->empty()) {
|
if (self->empty()) {
|
||||||
return true;
|
return S_OK;
|
||||||
}
|
}
|
||||||
auto top = *(self->stackPtr - 1);
|
auto top = *(self->stackPtr - 1);
|
||||||
self->maybeSkipWs();
|
self->maybeSkipWs();
|
||||||
MUSTTAIL return table[top](self);
|
MUSTTAIL return table[top](self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool string(Parser2 *self) {
|
static Status string(Parser2 *self) {
|
||||||
if (!self->parse_string()) {
|
if (Status s = self->parse_string()) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
self->pop();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
static bool colon(Parser2 *self) {
|
static Status colon(Parser2 *self) {
|
||||||
if (!self->parseLiteral(":")) {
|
if (Status s = self->parseLiteral(":")) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
self->pop();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
static bool value(Parser2 *self) {
|
static Status value(Parser2 *self) {
|
||||||
if (self->parse_string()) {
|
if (self->parse_string() == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parse_number()) {
|
} else if (self->parse_number() == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("{")) {
|
} else if (self->parseLiteral("{") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_begin_object(self->data);
|
self->callbacks->on_begin_object(self->data);
|
||||||
if (!self->push({N_OBJECT_VALUE_OR_END})) {
|
if (Status s = self->push({N_OBJECT_VALUE_OR_END})) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("[")) {
|
} else if (self->parseLiteral("[") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_begin_array(self->data);
|
self->callbacks->on_begin_array(self->data);
|
||||||
if (!self->push({N_ARRAY_VALUE_OR_END})) {
|
if (Status s = self->push({N_ARRAY_VALUE_OR_END})) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("true")) {
|
} else if (self->parseLiteral("true") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_true_literal(self->data);
|
self->callbacks->on_true_literal(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("false")) {
|
} else if (self->parseLiteral("false") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_false_literal(self->data);
|
self->callbacks->on_false_literal(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("null")) {
|
} else if (self->parseLiteral("null") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_null_literal(self->data);
|
self->callbacks->on_null_literal(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
static bool arrayOrEnd(Parser2 *self) {
|
static Status arrayOrEnd(Parser2 *self) {
|
||||||
if (self->parseLiteral("]")) {
|
if (self->parseLiteral("]") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_end_array(self->data);
|
self->callbacks->on_end_array(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else {
|
} else {
|
||||||
self->pop();
|
self->pop();
|
||||||
if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
if (Status s = self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static bool objectOrEnd(Parser2 *self) {
|
static Status objectOrEnd(Parser2 *self) {
|
||||||
if (self->parseLiteral("}")) {
|
if (self->parseLiteral("}") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_end_object(self->data);
|
self->callbacks->on_end_object(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else {
|
} else {
|
||||||
self->pop();
|
self->pop();
|
||||||
if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
if (Status s = self->push(
|
||||||
return false;
|
{T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
static bool arrayContinue(Parser2 *self) {
|
static Status arrayContinue(Parser2 *self) {
|
||||||
if (self->parseLiteral(",")) {
|
if (self->parseLiteral(",") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
if (Status s = self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
||||||
return false;
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("]")) {
|
} else if (self->parseLiteral("]") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_end_array(self->data);
|
self->callbacks->on_end_array(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
static bool objectContinue(Parser2 *self) {
|
static Status objectContinue(Parser2 *self) {
|
||||||
if (self->parseLiteral(",")) {
|
if (self->parseLiteral(",") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
if (Status s = self->push(
|
||||||
return false;
|
{T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
} else if (self->parseLiteral("}")) {
|
} else if (self->parseLiteral("}") == S_OK) {
|
||||||
self->pop();
|
self->pop();
|
||||||
self->callbacks->on_end_object(self->data);
|
self->callbacks->on_end_object(self->data);
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
return false;
|
return S_REJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr continuation table[N_PAST_END] = {
|
static constexpr continuation table[N_PAST_END] = {
|
||||||
@@ -635,14 +644,14 @@ private:
|
|||||||
assert(!empty());
|
assert(!empty());
|
||||||
--stackPtr;
|
--stackPtr;
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool push(std::initializer_list<Symbol> symbols) {
|
[[nodiscard]] Status push(std::initializer_list<Symbol> symbols) {
|
||||||
if (stackPtr >= std::end(stack) - symbols.size()) [[unlikely]] {
|
if (stackPtr >= std::end(stack) - symbols.size()) [[unlikely]] {
|
||||||
return false;
|
return S_OVERFLOW;
|
||||||
}
|
}
|
||||||
for (int i = symbols.size() - 1; i >= 0; --i) {
|
for (int i = symbols.size() - 1; i >= 0; --i) {
|
||||||
*stackPtr++ = *(symbols.begin() + i);
|
*stackPtr++ = *(symbols.begin() + i);
|
||||||
}
|
}
|
||||||
return true;
|
return S_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user