diff --git a/src/parser3.h b/src/parser3.h index d28b2a2..a20674c 100644 --- a/src/parser3.h +++ b/src/parser3.h @@ -17,20 +17,29 @@ namespace parser3 { -// Calling a continuation with buf == bufEnd means end of input -typedef PRESERVE_NONE WeaselJsonStatus (*Continuation)(struct Parser3 *, - char *buf, char *bufEnd); +// The internal result of a parse step: a WeaselJsonStatus value, or kBounce. +// It's a plain int (not WeaselJsonStatus) so the no-musttail trampoline's +// out-of-range sentinel never forms an out-of-range enum value (that would be +// UB, since the public WeaselJsonStatus has no fixed underlying type). parse() +// converts back to WeaselJsonStatus at the boundary, where it is always 0..3. +using ContinuationStatus = int; +[[maybe_unused]] inline constexpr ContinuationStatus kBounce = -1; -inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf, - char *bufEnd); -inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf, - char *bufEnd); -inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf, - char *bufEnd); -inline PRESERVE_NONE WeaselJsonStatus n_string(Parser3 *self, char *buf, - char *bufEnd); -inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf, - char *bufEnd); +// Calling a continuation with buf == bufEnd means end of input +typedef PRESERVE_NONE ContinuationStatus (*Continuation)(struct Parser3 *, + char *buf, + char *bufEnd); + +inline PRESERVE_NONE ContinuationStatus n_object2(Parser3 *self, char *buf, + char *bufEnd); +inline PRESERVE_NONE ContinuationStatus n_array2(Parser3 *self, char *buf, + char *bufEnd); +inline PRESERVE_NONE ContinuationStatus n_string2(Parser3 *self, char *buf, + char *bufEnd); +inline PRESERVE_NONE ContinuationStatus n_string(Parser3 *self, char *buf, + char *bufEnd); +inline PRESERVE_NONE ContinuationStatus n_number(Parser3 *self, char *buf, + char *bufEnd); // These appear in the stack of the pushdown // automata @@ -121,8 +130,8 @@ struct Parser3 { return *(stackPtr - 1); } - static PRESERVE_NONE WeaselJsonStatus keepGoing(Parser3 *self, char *buf, - char *bufEnd); + static PRESERVE_NONE ContinuationStatus keepGoing(Parser3 *self, char *buf, + char *bufEnd); Symbol *stack() const { return (Symbol *)(this + 1); } @@ -152,7 +161,8 @@ struct Parser3 { #endif }; -inline PRESERVE_NONE WeaselJsonStatus skipWhitespace(char *&buf, char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus skipWhitespace(char *&buf, + char *bufEnd) { constexpr int kStride = 4; for (;;) { if (bufEnd - buf < kStride) [[unlikely]] { @@ -171,8 +181,8 @@ inline PRESERVE_NONE WeaselJsonStatus skipWhitespace(char *&buf, char *bufEnd) { } } -inline PRESERVE_NONE WeaselJsonStatus n_whitespace(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_whitespace(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) { self->pop(); MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); @@ -184,8 +194,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_whitespace(Parser3 *self, char *buf, MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); } -inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_number(Parser3 *self, char *buf, + char *bufEnd) { if (buf != bufEnd) { buf = (char *)self->numDfa.scan(buf, bufEnd); if (buf == bufEnd) { @@ -204,9 +214,9 @@ inline PRESERVE_NONE WeaselJsonStatus n_number(Parser3 *self, char *buf, // Advance buf until double quote, backslash, invalid utf8, or codepoint < // 0x20 template -inline PRESERVE_NONE WeaselJsonStatus scan_string_impl(Parser3 *self, - char *&buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus scan_string_impl(Parser3 *self, + char *&buf, + char *bufEnd) { const auto before = buf; // Advance buf past characters that transition the accept state to itself @@ -253,34 +263,34 @@ inline PRESERVE_NONE WeaselJsonStatus scan_string_impl(Parser3 *self, #ifdef __x86_64__ constexpr int kLanes = 32; -template WeaselJsonStatus +template ContinuationStatus scan_string_impl>(Parser3 *, char *&, char *); -template __attribute__((target("avx2"))) WeaselJsonStatus +template __attribute__((target("avx2"))) ContinuationStatus scan_string_impl>(Parser3 *, char *&, char *); -__attribute__((target("default"))) inline PRESERVE_NONE WeaselJsonStatus +__attribute__((target("default"))) inline PRESERVE_NONE ContinuationStatus scan_string(Parser3 *self, char *&buf, char *bufEnd) { MUSTTAIL return scan_string_impl>( self, buf, bufEnd); } -__attribute__((target("avx2"))) inline PRESERVE_NONE WeaselJsonStatus +__attribute__((target("avx2"))) inline PRESERVE_NONE ContinuationStatus scan_string(Parser3 *self, char *&buf, char *bufEnd) { MUSTTAIL return scan_string_impl>( self, buf, bufEnd); } #else -inline PRESERVE_NONE WeaselJsonStatus scan_string(Parser3 *self, char *&buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus scan_string(Parser3 *self, char *&buf, + char *bufEnd) { MUSTTAIL return scan_string_impl>(self, buf, bufEnd); } #endif -inline PRESERVE_NONE WeaselJsonStatus n_value(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_value(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -392,8 +402,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_value(Parser3 *self, char *buf, MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); } -inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_object2(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -428,8 +438,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_object2(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_object3(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_object3(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -474,8 +484,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_object3(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_array2(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -500,8 +510,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_array2(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_array3(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_array3(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -532,8 +542,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_array3(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_string(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_string(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -559,8 +569,8 @@ inline int32_t read4_hex(const char *buf) { tables.hex[uint8_t(buf[2])] << 4 | tables.hex[uint8_t(buf[3])] << 0; } -inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_string2(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -661,9 +671,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_string_following_escape(Parser3 *self, - char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus +n_string_following_escape(Parser3 *self, char *buf, char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -701,8 +710,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_string_following_escape(Parser3 *self, MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); } -inline PRESERVE_NONE WeaselJsonStatus t_hex(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus t_hex(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -721,8 +730,8 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex(Parser3 *self, char *buf, MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); } -inline PRESERVE_NONE WeaselJsonStatus t_hex2(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus t_hex2(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -810,8 +819,8 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex2(Parser3 *self, char *buf, MUSTTAIL return Parser3::keepGoing(self, buf, bufEnd); } -inline PRESERVE_NONE WeaselJsonStatus t_hex3(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus t_hex3(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -872,9 +881,9 @@ inline PRESERVE_NONE WeaselJsonStatus t_hex3(Parser3 *self, char *buf, } template -inline PRESERVE_NONE WeaselJsonStatus singleCharInString(Parser3 *self, - char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus singleCharInString(Parser3 *self, + char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -891,8 +900,8 @@ inline PRESERVE_NONE WeaselJsonStatus singleCharInString(Parser3 *self, } } -inline PRESERVE_NONE WeaselJsonStatus n_true(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_true(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -909,8 +918,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_true(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_false(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_false(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -927,8 +936,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_false(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus n_null(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus n_null(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -946,8 +955,8 @@ inline PRESERVE_NONE WeaselJsonStatus n_null(Parser3 *self, char *buf, } template -inline PRESERVE_NONE WeaselJsonStatus singleChar(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus singleChar(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -963,8 +972,8 @@ inline PRESERVE_NONE WeaselJsonStatus singleChar(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus t_colon(Parser3 *self, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus t_colon(Parser3 *self, char *buf, + char *bufEnd) { if (buf == bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -985,8 +994,8 @@ inline PRESERVE_NONE WeaselJsonStatus t_colon(Parser3 *self, char *buf, } } -inline PRESERVE_NONE WeaselJsonStatus t_eof(Parser3 *, char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus t_eof(Parser3 *, char *buf, + char *bufEnd) { if (buf != bufEnd) [[unlikely]] { return WeaselJson_REJECT; } @@ -997,7 +1006,8 @@ constexpr inline struct ContinuationTable { constexpr ContinuationTable() { // Defaults for (int i = 0; i < N_SYMBOL_COUNT; ++i) { - continuations[i] = +[](struct Parser3 *, char *, char *) PRESERVE_NONE { + continuations[i] = +[](struct Parser3 *, char *, char *) + PRESERVE_NONE -> ContinuationStatus { printf("unimplemented\n"); return WeaselJson_REJECT; }; @@ -1035,26 +1045,30 @@ inline WeaselJsonStatus Parser3::parse(char *buf, int len) { this->dataBegin = this->writeBuf = buf; #ifdef HAS_MUSTTAIL - return symbolTables.continuations[top()](this, buf, buf + len); + // The continuation returns a value in 0..3 here (kBounce is only used by the + // no-musttail trampoline below), so the conversion back to the enum is in + // range. + return WeaselJsonStatus( + symbolTables.continuations[top()](this, buf, buf + len)); #else this->stashBufForTrampoline = buf; - WeaselJsonStatus result; + ContinuationStatus result; while ((result = symbolTables.continuations[top()]( - this, stashBufForTrampoline, buf + len)) == WeaselJsonStatus(-1)) + this, stashBufForTrampoline, buf + len)) == kBounce) ; - return result; + return WeaselJsonStatus(result); #endif } -inline PRESERVE_NONE WeaselJsonStatus Parser3::keepGoing(Parser3 *self, - char *buf, - char *bufEnd) { +inline PRESERVE_NONE ContinuationStatus Parser3::keepGoing(Parser3 *self, + char *buf, + char *bufEnd) { #ifdef HAS_MUSTTAIL MUSTTAIL return symbolTables.continuations[self->top()](self, buf, bufEnd); #else self->stashBufForTrampoline = buf; (void)bufEnd; - return WeaselJsonStatus(-1); + return kBounce; #endif }