123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- #include <library/cpp/json/fast_sax/unescape.h>
- #include <library/cpp/json/fast_sax/parser.h>
- #include <util/string/cast.h>
- #include <util/generic/buffer.h>
- #include <util/generic/strbuf.h>
- #include <util/generic/ymath.h>
- namespace NJson {
- enum EStoredStr {
- SS_NONE = 0, SS_NOCOPY, SS_MUSTCOPY
- };
- struct TParserCtx {
- TJsonCallbacks& Hndl;
- TBuffer Buffer;
- TStringBuf String;
- EStoredStr Stored = SS_NONE;
- bool ExpectValue = true;
- const char* p0 = nullptr;
- const char* p = nullptr;
- const char* pe = nullptr;
- const char* eof = nullptr;
- const char* ts = nullptr;
- const char* te = nullptr;
- int cs = 0;
- int act = 0;
- TParserCtx(TJsonCallbacks& h, TStringBuf data)
- : Hndl(h)
- , p0(data.data())
- , p(data.data())
- , pe(data.end())
- , eof(data.end())
- {}
- static inline bool GoodPtrs(const char* b, const char* e) {
- return b && e && b <= e;
- }
- bool OnError(TStringBuf reason = TStringBuf(""), bool end = false) const {
- size_t off = 0;
- TStringBuf token;
- if (GoodPtrs(p0, ts)) {
- off = ts - p0;
- } else if (end && GoodPtrs(p0, pe)) {
- off = pe - p0;
- }
- if (GoodPtrs(ts, te)) {
- token = TStringBuf(ts, te);
- }
- if (!token) {
- Hndl.OnError(off, reason);
- } else {
- Hndl.OnError(off, TString::Join(reason, " at token: '", token, "'"));
- }
- return false;
- }
- bool OnVal() {
- if (Y_UNLIKELY(!ExpectValue)) {
- return false;
- }
- ExpectValue = false;
- return true;
- }
- bool OnNull() {
- return Y_LIKELY(OnVal())
- && Hndl.OnNull();
- }
- bool OnTrue() {
- return Y_LIKELY(OnVal())
- && Hndl.OnBoolean(true);
- }
- bool OnFalse() {
- return Y_LIKELY(OnVal())
- && Hndl.OnBoolean(false);
- }
- bool OnPInt() {
- unsigned long long res = 0;
- return Y_LIKELY(OnVal())
- && TryFromString<unsigned long long>(TStringBuf(ts, te), res)
- && Hndl.OnUInteger(res);
- }
- bool OnNInt() {
- long long res = 0;
- return Y_LIKELY(OnVal())
- && TryFromString<long long>(TStringBuf(ts, te), res)
- && Hndl.OnInteger(res);
- }
- bool OnFlt() {
- double res = 0;
- return Y_LIKELY(OnVal())
- && TryFromString<double>(TStringBuf(ts, te), res)
- && IsFinite(res)
- && Hndl.OnDouble(res);
- }
- bool OnMapOpen() {
- bool res = Y_LIKELY(OnVal())
- && Hndl.OnOpenMap();
- ExpectValue = true;
- return res;
- }
- bool OnArrOpen() {
- bool res = Y_LIKELY(OnVal())
- && Hndl.OnOpenArray();
- ExpectValue = true;
- return res;
- }
- bool OnString(TStringBuf s, EStoredStr t) {
- if (Y_LIKELY(OnVal())) {
- String = s;
- Stored = t;
- return true;
- } else {
- return false;
- }
- }
- bool OnStrU() {
- return OnString(TStringBuf(ts, te), SS_NOCOPY);
- }
- bool OnStrQ() {
- return OnString(TStringBuf(ts + 1, te - 1), SS_NOCOPY);
- }
- bool OnStrE() {
- Buffer.Clear();
- Buffer.Reserve(2 * (te - ts));
- return OnString(UnescapeJsonUnicode(TStringBuf(ts + 1, te - ts - 2), Buffer.data()), SS_MUSTCOPY);
- }
- bool OnMapClose() {
- ExpectValue = false;
- return Y_LIKELY(OnAfterVal())
- && Hndl.OnCloseMap();
- }
- bool OnArrClose() {
- ExpectValue = false;
- return Y_LIKELY(OnAfterVal())
- && Hndl.OnCloseArray();
- }
- bool OnColon() {
- if (ExpectValue) {
- return false;
- }
- ExpectValue = true;
- const auto stored = Stored;
- Stored = SS_NONE;
- switch (stored) {
- default:
- return false;
- case SS_NOCOPY:
- return Hndl.OnMapKeyNoCopy(String);
- case SS_MUSTCOPY:
- return Hndl.OnMapKey(String);
- }
- }
- bool OnAfterVal() {
- const auto stored = Stored;
- Stored = SS_NONE;
- switch (stored) {
- default:
- return true;
- case SS_NOCOPY:
- return Hndl.OnStringNoCopy(String);
- case SS_MUSTCOPY:
- return Hndl.OnString(String);
- }
- }
- bool OnComma() {
- if (Y_UNLIKELY(ExpectValue)) {
- return false;
- }
- ExpectValue = true;
- return OnAfterVal();
- }
- bool Parse();
- };
- #if 0
- %%{
- machine fastjson;
- alphtype char;
- action OnNull { if (Y_UNLIKELY(!OnNull())) goto TOKEN_ERROR; }
- action OnTrue { if (Y_UNLIKELY(!OnTrue())) goto TOKEN_ERROR; }
- action OnFalse { if (Y_UNLIKELY(!OnFalse())) goto TOKEN_ERROR; }
- action OnPInt { if (Y_UNLIKELY(!OnPInt())) goto TOKEN_ERROR; }
- action OnNInt { if (Y_UNLIKELY(!OnNInt())) goto TOKEN_ERROR; }
- action OnFlt { if (Y_UNLIKELY(!OnFlt())) goto TOKEN_ERROR; }
- action OnStrU { if (Y_UNLIKELY(!OnStrU())) goto TOKEN_ERROR; }
- action OnStrQ { if (Y_UNLIKELY(!OnStrQ())) goto TOKEN_ERROR; }
- action OnStrE { if (Y_UNLIKELY(!OnStrE())) goto TOKEN_ERROR; }
- action OnDictO { if (Y_UNLIKELY(!OnMapOpen())) goto TOKEN_ERROR; }
- action OnDictC { if (Y_UNLIKELY(!OnMapClose())) goto TOKEN_ERROR; }
- action OnArrO { if (Y_UNLIKELY(!OnArrOpen())) goto TOKEN_ERROR; }
- action OnArrC { if (Y_UNLIKELY(!OnArrClose())) goto TOKEN_ERROR; }
- action OnComma { if (Y_UNLIKELY(!OnComma())) goto TOKEN_ERROR; }
- action OnColon { if (Y_UNLIKELY(!OnColon())) goto TOKEN_ERROR; }
- action OnError { goto TOKEN_ERROR; }
- comment1 = "/*" (any* -- "*/") "*/";
- pint = [0-9]+;
- nint = '-'[0-9]+;
- flt = '-'?[0-9.][0-9.eE+\-]+;
- uchar0 = [a-zA-Z_@$] | (0x80 .. 0xFF);
- uchar = uchar0 | digit | [.\-];
- qchar = [^'\\]; #';
- dchar = [^"\\]; #";
- echar = "\\" any;
- qechar = qchar | echar;
- dechar = dchar | echar;
- strq = "'" qchar* "'";
- strd = '"' dchar* '"';
- strqe = "'" qechar* "'";
- strde = '"' dechar* '"';
- strU = uchar0 uchar*;
- strQ = strq | strd;
- strE = strqe | strde;
- ws = (0x00 .. 0x20) | 0x7F;
- sp = ws+;
- main := |*
- 'null' => OnNull;
- 'true' => OnTrue;
- 'false' => OnFalse;
- pint => OnPInt;
- nint => OnNInt;
- flt => OnFlt;
- strU => OnStrU;
- strQ => OnStrQ;
- strE => OnStrE;
- ',' => OnComma;
- ':' => OnColon;
- '{' => OnDictO;
- '}' => OnDictC;
- '[' => OnArrO;
- ']' => OnArrC;
- sp;
- comment1;
- (flt | pint | nint) (any - (ws | ',' | ':' | '{' | '}' | '[' | ']')) => OnError;
- any => OnError;
- *|;
- }%%
- #endif
- bool TParserCtx::Parse() {
- try {
- %%{
- write data noerror nofinal;
- write init;
- write exec;
- }%%
- Y_UNUSED(fastjson_en_main);
- } catch (const TFromStringException& e) {
- return OnError(e.what());
- }
- return OnAfterVal() && Hndl.OnEnd() || OnError("invalid or truncated", true);
- TOKEN_ERROR:
- return OnError("invalid syntax");
- }
- bool ReadJsonFast(TStringBuf data, TJsonCallbacks* h) {
- return TParserCtx(*h, data).Parse();
- }
- }
|