scimpl_select.rl6 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #include <library/cpp/scheme/scimpl.h>
  2. #include <util/string/cast.h>
  3. #include <util/string/escape.h>
  4. #include <library/cpp/string_utils/relaxed_escaper/relaxed_escaper.h>
  5. #include <util/generic/is_in.h>
  6. #include <util/string/util.h>
  7. namespace NSc {
  8. template <typename TValue, typename TGetter>
  9. struct TSelector {
  10. TValue& Root;
  11. TValue* Current = nullptr;
  12. TValue* Parent = nullptr;
  13. TStringBuf CurrentDictKey;
  14. size_t CurrentArrayKey = 0;
  15. size_t Depth = 0;
  16. bool HasArray = false;
  17. bool HasError = false;
  18. TSelector(TValue& root)
  19. : Root(root)
  20. , Current(&Root)
  21. {}
  22. template <typename T>
  23. bool Next(T k) {
  24. Depth += 1;
  25. Parent = Current;
  26. Current = TGetter::Next(Current, k);
  27. return Current != nullptr;
  28. }
  29. bool NextDict(TStringBuf k) {
  30. return Next(CurrentDictKey = k);
  31. }
  32. bool NextArray(size_t k) {
  33. HasArray = true;
  34. return Next(CurrentArrayKey = k);
  35. }
  36. bool Error() {
  37. Parent = nullptr;
  38. Current = nullptr;
  39. CurrentArrayKey = 0;
  40. CurrentDictKey = TStringBuf();
  41. HasError = true;
  42. return false;
  43. }
  44. };
  45. template <typename TSelector>
  46. struct TSelectorCtx {
  47. TSelector Selector;
  48. TString Buffer;
  49. const char* p0 = nullptr;
  50. const char* p = nullptr;
  51. const char* pe = nullptr;
  52. const char* eof = nullptr;
  53. const char* ts = nullptr;
  54. const char* te = nullptr;
  55. int cs = 0;
  56. int act = 0;
  57. TSelectorCtx(TSelector sel, TStringBuf data)
  58. : Selector(sel)
  59. , p0(data.data())
  60. , p(data.data())
  61. , pe(data.end())
  62. , eof(data.end())
  63. {}
  64. bool OnString(TStringBuf s) {
  65. return Selector.NextDict(s);
  66. }
  67. bool OnInt(size_t k) {
  68. return Selector.NextArray(k);
  69. }
  70. bool OnStrU() {
  71. return OnString(TStringBuf(ts, te));
  72. }
  73. bool OnStrQ() {
  74. return OnString(TStringBuf(ts + 1, te - 1));
  75. }
  76. bool OnStrE() {
  77. Buffer.clear();
  78. Buffer.reserve(te - ts);
  79. UnescapeC(ts + 1, te - ts - 2, Buffer);
  80. return OnString(Buffer);
  81. }
  82. bool OnIntU() {
  83. return OnInt(FromString<ui32>(TStringBuf(ts, te)));
  84. }
  85. bool OnIntQ() {
  86. return OnInt(FromString<ui32>(TStringBuf(ts + 1, te - 1)));
  87. }
  88. bool OnError() {
  89. Selector.Error();
  90. return false;
  91. }
  92. bool SelectPath();
  93. };
  94. #if 0
  95. %%{
  96. machine schemeselect;
  97. alphtype char;
  98. action OnIntU { if (Y_UNLIKELY(!OnIntU())) goto TOKEN_ERROR; }
  99. action OnIntQ { if (Y_UNLIKELY(!OnIntQ())) goto TOKEN_ERROR; }
  100. action OnStrU { if (Y_UNLIKELY(!OnStrU())) goto TOKEN_ERROR; }
  101. action OnStrQ { if (Y_UNLIKELY(!OnStrQ())) goto TOKEN_ERROR; }
  102. action OnStrE { if (Y_UNLIKELY(!OnStrE())) goto TOKEN_ERROR; }
  103. action OnError { goto TOKEN_ERROR; }
  104. intu = [0-9]+;
  105. intq = '[' intu ']';
  106. uchar0 = [a-zA-Z_@$] | (0x80 .. 0xFF);
  107. uchar = uchar0 | digit | [.\-];
  108. qchar = [^'\\]; #';
  109. dchar = [^"\\]; #";
  110. bchar = [^\]\\];
  111. echar = "\\" any;
  112. qechar = qchar | echar;
  113. dechar = dchar | echar;
  114. bechar = bchar | echar;
  115. strq = "'" qchar* "'";
  116. strd = '"' dchar* '"';
  117. strb = '[' bchar* ']';
  118. strqe = "'" qechar* "'";
  119. strde = '"' dechar* '"';
  120. strbe = '[' bechar* ']';
  121. strU = uchar0 uchar*;
  122. strQ = strq | strd | strb;
  123. strE = strqe | strde | strbe;
  124. main := |*
  125. intu => OnIntU;
  126. intq => OnIntQ;
  127. strU => OnStrU;
  128. strQ => OnStrQ;
  129. strE => OnStrE;
  130. '/';
  131. (intu) (any - ('/' | '[' )) => OnError;
  132. any => OnError;
  133. *|;
  134. }%%
  135. #endif
  136. template <typename TSelector>
  137. bool TSelectorCtx<TSelector>::SelectPath() {
  138. try {
  139. %%{
  140. write data noerror nofinal;
  141. write init;
  142. write exec;
  143. }%%
  144. ;
  145. Y_UNUSED(schemeselect_en_main);
  146. } catch (const TFromStringException&) {
  147. return OnError();
  148. }
  149. return Selector.Current;
  150. TOKEN_ERROR:
  151. return OnError();
  152. }
  153. template <bool CheckHas>
  154. struct TGetNext {
  155. template <typename TValue, typename TIdx>
  156. static TValue* Next(TValue* val, TIdx idx) {
  157. if (val) {
  158. if (CheckHas && !val->Has(idx)) {
  159. return nullptr;
  160. } else {
  161. return &(*val)[idx];
  162. }
  163. } else {
  164. return nullptr;
  165. }
  166. }
  167. };
  168. const TValue& TValue::TrySelect(TStringBuf path) const {
  169. TSelectorCtx<TSelector<const TValue, TGetNext<true> > > ctx(*this, path);
  170. if (ctx.SelectPath()) {
  171. return *ctx.Selector.Current;
  172. }
  173. return DefaultValue();
  174. }
  175. TValue* TValue::TrySelectOrAdd(TStringBuf path) {
  176. TSelectorCtx<TSelector<TValue, TGetNext<false> > > ctx(*this, path);
  177. if (ctx.SelectPath()) {
  178. return ctx.Selector.Current;
  179. } else {
  180. return nullptr;
  181. }
  182. }
  183. TValue TValue::TrySelectAndDelete(TStringBuf path) {
  184. TSelectorCtx<TSelector<TValue, TGetNext<true> > > ctx(*this, path);
  185. if (ctx.SelectPath() && ctx.Selector.Parent) {
  186. if (ctx.Selector.Parent->IsArray()) {
  187. return ctx.Selector.Parent->Delete(ctx.Selector.CurrentArrayKey);
  188. } else if (ctx.Selector.Parent->IsDict()) {
  189. return ctx.Selector.Parent->Delete(ctx.Selector.CurrentDictKey);
  190. } else {
  191. Y_ASSERT(false);
  192. return DefaultValue();
  193. }
  194. } else {
  195. return DefaultValue();
  196. }
  197. }
  198. bool TValue::PathExists(TStringBuf path) const {
  199. return TSelectorCtx<TSelector<const TValue, TGetNext<true>>>(*this, path).SelectPath();
  200. }
  201. bool TValue::PathValid(TStringBuf path) {
  202. TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), path);
  203. return ctx.SelectPath() || !ctx.Selector.HasError;
  204. }
  205. TString TValue::EscapeForPath(TStringBuf rawKey) {
  206. static const str_spn danger{"/[]"};
  207. if (!rawKey || danger.brk(rawKey.begin(), rawKey.end()) != rawKey.end()) {
  208. return NEscJ::EscapeJ<true>(rawKey);
  209. }
  210. TSelectorCtx<TSelector<const TValue, TGetNext<false>>> ctx(DefaultValue(), rawKey);
  211. ctx.SelectPath();
  212. if (ctx.Selector.HasError || ctx.Selector.Depth > 1 || ctx.Selector.HasArray) {
  213. return NEscJ::EscapeJ<true>(rawKey);
  214. } else {
  215. return ToString(rawKey);
  216. }
  217. }
  218. }