list_builtin.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #include "list_builtin.h"
  2. using namespace NYql;
  3. namespace NSQLTranslationV0 {
  4. TAstNode* TListBuiltin::Translate(TContext& ctx) const {
  5. Y_UNUSED(ctx);
  6. Y_DEBUG_ABORT_UNLESS(Node);
  7. return Node->Translate(ctx);
  8. }
  9. TNodePtr TListBuiltin::GetIdentityLambda() {
  10. return BuildLambda(Pos, Y("arg"), Y(), "arg");
  11. }
  12. TNodePtr TListBuiltin::SkipEmpty(TNodePtr arg) {
  13. auto sameArgLambda = BuildLambda(Pos, Y(), AstNode("item"));
  14. auto handleNotSkippableType = BuildLambda(Pos, Y(), Y("Just", "item"));
  15. auto checkOptional = Y("MatchType", "item", Q("Optional"),
  16. sameArgLambda, handleNotSkippableType);
  17. auto checkOptionalLambda = BuildLambda(Pos, Y(), checkOptional);
  18. auto checkList = Y("MatchType", "item", Q("List"),
  19. sameArgLambda, checkOptionalLambda);
  20. return Y("OrderedFlatMap", arg, BuildLambda(Pos, Y("item"), checkList));
  21. }
  22. bool TListSortBuiltin::DoInit(TContext& ctx, ISource* src) {
  23. if (Args.size() < 1 || Args.size() > 2) {
  24. ctx.Error(Pos) << "List" << OpName
  25. << " requires one or two parameters";
  26. return false;
  27. }
  28. if (!Args[0]->Init(ctx, src)) {
  29. return false;
  30. }
  31. if (Args.size() == 2) {
  32. if (!Args[1]->Init(ctx, src)) {
  33. return false;
  34. }
  35. } else {
  36. Args.push_back(GetIdentityLambda());
  37. }
  38. Node = Y(OpName, SkipEmpty(Args[0]), Y("Bool", Q(Asc ? "true" : "false")), Args[1]);
  39. return true;
  40. }
  41. bool TListExtractBuiltin::DoInit(TContext& ctx, ISource* src) {
  42. if (Args.size() != 2) {
  43. ctx.Error(Pos) << "List" << OpName
  44. << " requires exactly two parameters";
  45. return false;
  46. }
  47. if (!Args[0]->Init(ctx, src)) {
  48. return false;
  49. }
  50. if (!Args[1]->Init(ctx, src)) {
  51. return false;
  52. }
  53. Args[1] = MakeAtomFromExpression(ctx, Args[1]).Build();
  54. Node = Y(OpName, SkipEmpty(Args[0]), Args[1]);
  55. return true;
  56. }
  57. bool TListProcessBuiltin::CheckArgs(TContext& ctx, ISource* src) {
  58. if (Args.size() < 2 ) {
  59. ctx.Error(Pos) << "List" << OpName
  60. << " requires at least two parameters";
  61. return false;
  62. }
  63. for (const auto& arg : Args) {
  64. if (!arg->Init(ctx, src)) {
  65. return false;
  66. }
  67. }
  68. OpLiteral = Args[1]->GetLiteral("String");
  69. return true;
  70. }
  71. TNodePtr TListProcessBuiltin::PrepareResult() {
  72. TNodePtr result;
  73. if (OpLiteral) {
  74. size_t modulePos = OpLiteral->find("::");
  75. if (modulePos != TString::npos) {
  76. const TString& module = OpLiteral->substr(0, modulePos);
  77. const TString& function = OpLiteral->substr(modulePos + 2);
  78. auto udf = Y("Udf", Q(module + "." + function));
  79. result = Y("Apply", udf, "item");
  80. } else {
  81. result = Y(*OpLiteral, "item");
  82. }
  83. } else {
  84. result = Y("Apply", Args[1], "item");
  85. }
  86. for (size_t i = 0; i < Args.size(); ++i) {
  87. if (i > 1) {
  88. result->Add(Args[i]);
  89. }
  90. }
  91. return result;
  92. }
  93. bool TListMapBuiltin::DoInit(TContext& ctx, ISource* src) {
  94. if (!CheckArgs(ctx, src)) {
  95. return false;
  96. };
  97. auto prepare = PrepareResult();
  98. auto just = BuildLambda(Pos, Y(), Y("Just", prepare));
  99. auto sameArgLambda = BuildLambda(Pos, Y(), prepare);
  100. auto match = Y("MatchType", prepare, Q("Data"), just, sameArgLambda);
  101. auto lambda = Flat ? BuildLambda(Pos, Y("item"), match) : GetMapLambda();
  102. Node = Y(OpName,
  103. Flat ? SkipEmpty(Args[0]) : Args[0],
  104. lambda
  105. );
  106. return true;
  107. }
  108. TNodePtr TListMapBuiltin::GetMapLambda() {
  109. return BuildLambda(Pos, Y("item"), PrepareResult());
  110. }
  111. bool TListFilterBuiltin::DoInit(TContext& ctx, ISource* src) {
  112. if (!CheckArgs(ctx, src)) {
  113. return false;
  114. };
  115. Node = Y("OrderedFlatMap",
  116. SkipEmpty(Args[0]),
  117. GetFilterLambda()
  118. );
  119. return true;
  120. }
  121. TNodePtr TListFilterBuiltin::GetFilterLambda() {
  122. return BuildLambda(Pos, Y("item"), Y("OptionalIf", Y("Coalesce", PrepareResult(), Y("Bool", Q("false"))), "item"));
  123. }
  124. bool TListFoldBuiltin::DoInit(TContext& ctx, ISource* src) {
  125. if (Args.size() != ArgCount) {
  126. ctx.Error(Pos) << "Folding list with " << OpName << "requires exactly " << ArgCount << " parameter";
  127. return false;
  128. }
  129. for (const auto& arg : Args) {
  130. if (!arg->Init(ctx, src)) {
  131. return false;
  132. }
  133. }
  134. Node = Y("Fold",
  135. SkipEmpty(Args[0]),
  136. GetInitialState(),
  137. GetUpdateLambda()
  138. );
  139. return true;
  140. }
  141. TNodePtr TListFoldBuiltin::GetInitialState() {
  142. return Y(StateType, Q(StateValue));
  143. }
  144. TNodePtr TListFoldBuiltin::GetUpdateLambda() {
  145. return BuildLambda(Pos, Y("item", "state"), Y(OpName, "item", "state"));
  146. }
  147. TNodePtr TListCountBuiltin::GetUpdateLambda() {
  148. return BuildLambda(Pos, Y("item", "state"), Y(OpName, "state"));
  149. }
  150. bool TListAvgBuiltin::DoInit(TContext& ctx, ISource* src) {
  151. if (TListFoldBuiltin::DoInit(ctx, src)) {
  152. auto foldResult = Node;
  153. Node = Y("Div", Y("Nth", foldResult, Q("1")), Y("Nth", foldResult, Q("0")));
  154. return true;
  155. } else {
  156. return false;
  157. }
  158. }
  159. TNodePtr TListAvgBuiltin::GetInitialState() {
  160. return Q(Y(Y("Uint64", Q("0")), Y("Double", Q("0"))));
  161. }
  162. TNodePtr TListAvgBuiltin::GetUpdateLambda() {
  163. auto count = Y("Inc", Y("Nth", "state", Q("0")));
  164. auto sum = Y("Add", "item", Y("Nth", "state", Q("1")));
  165. return BuildLambda(Pos, Y("item", "state"), Q(Y(count, sum)));
  166. }
  167. TNodePtr TListHasBuiltin::GetUpdateLambda() {
  168. return BuildLambda(Pos, Y("item", "state"), Y("Or", "state",
  169. Y("Coalesce", Y(OpName, "item", Args[1]), Y("Bool", Q("false")))));
  170. }
  171. bool TListFold1Builtin::DoInit(TContext& ctx, ISource* src) {
  172. if (Args.size() != 1) {
  173. ctx.Error(Pos) << "Folding list with " << OpName << " requires only one parameter";
  174. return false;
  175. }
  176. if (!Args[0]->Init(ctx, src)) {
  177. return false;
  178. }
  179. Node = Y("Fold1",
  180. SkipEmpty(Args[0]),
  181. GetInitLambda(),
  182. GetUpdateLambda()
  183. );
  184. return true;
  185. }
  186. TNodePtr TListFold1Builtin::GetInitLambda() {
  187. return GetIdentityLambda();
  188. }
  189. TNodePtr TListFold1Builtin::GetUpdateLambda() {
  190. return BuildLambda(Pos, Y("item", "state"), Y(OpName, "state", "item"));
  191. }
  192. bool TListUniqBuiltin::DoInit(TContext& ctx, ISource* src) {
  193. if (Args.size() != 1) {
  194. ctx.Error(Pos) << OpName << " requires only one parameter";
  195. return false;
  196. }
  197. if (!Args[0]->Init(ctx, src)) {
  198. return false;
  199. }
  200. Node = Y("DictKeys",
  201. Y("ToDict", Args[0], GetIdentityLambda(), BuildLambda(Pos, Y("item"), Y("Void")), Q(Y(Q("Hashed"), Q("One"))))
  202. );
  203. return true;
  204. }
  205. bool TListCreateBuiltin::DoInit(TContext& ctx, ISource* src) {
  206. if (Args.size() != 1) {
  207. ctx.Error(Pos) << OpName << " requires only one parameter";
  208. return false;
  209. }
  210. if (!Args[0]->Init(ctx, src)) {
  211. return false;
  212. }
  213. auto literal = Args[0]->GetLiteral("String");
  214. if (literal) {
  215. Node = Y("List",
  216. Y("ListType",
  217. Y("ParseType", Q(*literal))));
  218. } else {
  219. Node = Y("List",
  220. Y("ListType", Args[0]));
  221. }
  222. return true;
  223. }
  224. bool TDictCreateBuiltin::DoInit(TContext& ctx, ISource* src) {
  225. if (Args.size() != 2) {
  226. ctx.Error(Pos) << OpName << " requires two parameters";
  227. return false;
  228. }
  229. TNodePtr types[2];
  230. for (ui32 i = 0; i < 2; ++i) {
  231. if (!Args[i]->Init(ctx, src)) {
  232. return false;
  233. }
  234. auto literal = Args[i]->GetLiteral("String");
  235. if (literal) {
  236. types[i] = Y("ParseType", Q(*literal));
  237. } else {
  238. types[i] = Args[i];
  239. }
  240. }
  241. Node = Y("Dict",
  242. Y("DictType", types[0], types[1]));
  243. return true;
  244. }
  245. } // namespace NSQLTranslationV0