123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- #include <library/cpp/scheme/scimpl.h>
- #include <util/string/cast.h>
- #include <util/string/escape.h>
- #include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
- #include <util/generic/is_in.h>
- #include <util/string/util.h>
- namespace NSc {
- template <typename TValue, typename TGetter>
- struct TSelector {
- TValue& Root;
- TValue* Current = nullptr;
- TValue* Parent = nullptr;
- TStringBuf CurrentDictKey;
- size_t CurrentArrayKey = 0;
- size_t Depth = 0;
- bool HasArray = false;
- bool HasError = false;
- TSelector(TValue& root)
- : Root(root)
- , Current(&Root)
- {}
- template <typename T>
- bool Next(T k) {
- Depth += 1;
- Parent = Current;
- Current = TGetter::Next(Current, k);
- return Current != nullptr;
- }
- bool NextDict(TStringBuf k) {
- return Next(CurrentDictKey = k);
- }
- bool NextArray(size_t k) {
- HasArray = true;
- return Next(CurrentArrayKey = k);
- }
- bool Error() {
- Parent = nullptr;
- Current = nullptr;
- CurrentArrayKey = 0;
- CurrentDictKey = TStringBuf();
- HasError = true;
- return false;
- }
- };
- template <typename TSelector>
- struct TSelectorCtx {
- TSelector Selector;
- TString Buffer;
- 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;
- TSelectorCtx(TSelector sel, TStringBuf data)
- : Selector(sel)
- , p0(data.data())
- , p(data.data())
- , pe(data.end())
- , eof(data.end())
- {}
- bool OnString(TStringBuf s) {
- return Selector.NextDict(s);
- }
- bool OnInt(size_t k) {
- return Selector.NextArray(k);
- }
- bool OnStrU() {
- return OnString(TStringBuf(ts, te));
- }
- bool OnStrQ() {
- return OnString(TStringBuf(ts + 1, te - 1));
- }
- bool OnStrE() {
- Buffer.clear();
- Buffer.reserve(te - ts);
- UnescapeC(ts + 1, te - ts - 2, Buffer);
- return OnString(Buffer);
- }
- bool OnIntU() {
- return OnInt(FromString<ui32>(TStringBuf(ts, te)));
- }
- bool OnIntQ() {
- return OnInt(FromString<ui32>(TStringBuf(ts + 1, te - 1)));
- }
- bool OnError() {
- Selector.Error();
- return false;
- }
- bool SelectPath();
- };
- #if 0
- %%{
- machine schemeselect;
- alphtype char;
- action OnIntU { if (Y_UNLIKELY(!OnIntU())) goto TOKEN_ERROR; }
- action OnIntQ { if (Y_UNLIKELY(!OnIntQ())) 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 OnError { goto TOKEN_ERROR; }
- intu = [0-9]+;
- intq = '[' intu ']';
- uchar0 = [a-zA-Z_@$] | (0x80 .. 0xFF);
- uchar = uchar0 | digit | [.\-];
- qchar = [^'\\]; #';
- dchar = [^"\\]; #";
- bchar = [^\]\\];
- echar = "\\" any;
- qechar = qchar | echar;
- dechar = dchar | echar;
- bechar = bchar | echar;
- strq = "'" qchar* "'";
- strd = '"' dchar* '"';
- strb = '[' bchar* ']';
- strqe = "'" qechar* "'";
- strde = '"' dechar* '"';
- strbe = '[' bechar* ']';
- strU = uchar0 uchar*;
- strQ = strq | strd | strb;
- strE = strqe | strde | strbe;
- main := |*
- intu => OnIntU;
- intq => OnIntQ;
- strU => OnStrU;
- strQ => OnStrQ;
- strE => OnStrE;
- '/';
- (intu) (any - ('/' | '[' )) => OnError;
- any => OnError;
- *|;
- }%%
- #endif
- template <typename TSelector>
- bool TSelectorCtx<TSelector>::SelectPath() {
- try {
- %%{
- write data noerror nofinal;
- write init;
- write exec;
- }%%
- ;
- Y_UNUSED(schemeselect_en_main);
- } catch (const TFromStringException&) {
- return OnError();
- }
- return Selector.Current;
- TOKEN_ERROR:
- return OnError();
- }
- template <bool CheckHas>
- struct TGetNext {
- template <typename TValue, typename TIdx>
- static TValue* Next(TValue* val, TIdx idx) {
- if (val) {
- if (CheckHas && !val->Has(idx)) {
- return nullptr;
- } else {
- return &(*val)[idx];
- }
- } else {
- return nullptr;
- }
- }
- };
- const TValue& TValue::TrySelect(TStringBuf path) const {
- TSelectorCtx<TSelector<const TValue, TGetNext<true> > > ctx(*this, path);
- if (ctx.SelectPath()) {
- return *ctx.Selector.Current;
- }
- return DefaultValue();
- }
- TValue* TValue::TrySelectOrAdd(TStringBuf path) {
- TSelectorCtx<TSelector<TValue, TGetNext<false> > > ctx(*this, path);
- if (ctx.SelectPath()) {
- return ctx.Selector.Current;
- } else {
- return nullptr;
- }
- }
- TValue TValue::TrySelectAndDelete(TStringBuf path) {
- TSelectorCtx<TSelector<TValue, TGetNext<true> > > ctx(*this, path);
- if (ctx.SelectPath() && ctx.Selector.Parent) {
- if (ctx.Selector.Parent->IsArray()) {
- return ctx.Selector.Parent->Delete(ctx.Selector.CurrentArrayKey);
- } else if (ctx.Selector.Parent->IsDict()) {
- return ctx.Selector.Parent->Delete(ctx.Selector.CurrentDictKey);
- } else {
- Y_ASSERT(false);
- return DefaultValue();
- }
- } else {
- return DefaultValue();
- }
- }
- bool TValue::PathExists(TStringBuf path) const {
- return TSelectorCtx<TSelector<const TValue, TGetNext<true>>>(*this, path).SelectPath();
- }
- bool TValue::PathValid(TStringBuf path) {
- TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), path);
- return ctx.SelectPath() || !ctx.Selector.HasError;
- }
- TString TValue::EscapeForPath(TStringBuf rawKey) {
- static const str_spn danger{"/[]"};
- if (!rawKey || danger.brk(rawKey.begin(), rawKey.end()) != rawKey.end()) {
- return NEscJ::EscapeJ<true>(rawKey);
- }
- TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), rawKey);
- ctx.SelectPath();
- if (ctx.Selector.HasError || ctx.Selector.Depth > 1 || ctx.Selector.HasArray) {
- return NEscJ::EscapeJ<true>(rawKey);
- } else {
- return ToString(rawKey);
- }
- }
- }
|