format.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #include "check_runner.h"
  2. #include <yql/essentials/sql/v1/format/sql_format.h>
  3. #include <yql/essentials/sql/v1/lexer/antlr4/lexer.h>
  4. #include <yql/essentials/sql/v1/lexer/antlr4_ansi/lexer.h>
  5. #include <yql/essentials/sql/v1/proto_parser/antlr4/proto_parser.h>
  6. #include <yql/essentials/sql/v1/proto_parser/antlr4_ansi/proto_parser.h>
  7. #include <util/string/builder.h>
  8. namespace NYql {
  9. namespace NFastCheck {
  10. namespace {
  11. constexpr size_t FormatContextLimit = 100;
  12. class TFormatRunner : public ICheckRunner {
  13. public:
  14. TString GetCheckName() const final {
  15. return "format";
  16. }
  17. TCheckResponse Run(const TChecksRequest& request) final {
  18. switch (request.Syntax) {
  19. case ESyntax::SExpr:
  20. return RunSExpr(request);
  21. case ESyntax::PG:
  22. return RunPg(request);
  23. case ESyntax::YQL:
  24. return RunYql(request);
  25. }
  26. }
  27. private:
  28. TCheckResponse RunSExpr(const TChecksRequest& request) {
  29. Y_UNUSED(request);
  30. // no separate check for format here
  31. return TCheckResponse{.CheckName = GetCheckName(), .Success = true};
  32. }
  33. TCheckResponse RunPg(const TChecksRequest& request) {
  34. Y_UNUSED(request);
  35. // no separate check for format here
  36. return TCheckResponse{.CheckName = GetCheckName(), .Success = true};
  37. }
  38. TCheckResponse RunYql(const TChecksRequest& request) {
  39. TCheckResponse res {.CheckName = GetCheckName()};
  40. if (request.SyntaxVersion != 1) {
  41. res.Issues.AddIssue(TIssue({}, "Only SyntaxVersion 1 is supported"));
  42. return res;
  43. }
  44. google::protobuf::Arena arena;
  45. NSQLTranslation::TTranslationSettings settings;
  46. settings.Arena = &arena;
  47. settings.File = request.File;
  48. settings.Antlr4Parser = true;
  49. settings.AnsiLexer = request.IsAnsiLexer;
  50. NSQLTranslationV1::TLexers lexers;
  51. lexers.Antlr4 = NSQLTranslationV1::MakeAntlr4LexerFactory();
  52. lexers.Antlr4Ansi = NSQLTranslationV1::MakeAntlr4AnsiLexerFactory();
  53. NSQLTranslationV1::TParsers parsers;
  54. parsers.Antlr4 = NSQLTranslationV1::MakeAntlr4ParserFactory();
  55. parsers.Antlr4Ansi = NSQLTranslationV1::MakeAntlr4AnsiParserFactory();
  56. auto formatter = NSQLFormat::MakeSqlFormatter(lexers, parsers, settings);
  57. TString formattedQuery;
  58. res.Success = formatter->Format(request.Program, formattedQuery, res.Issues);
  59. if (res.Success && formattedQuery != request.Program) {
  60. res.Success = false;
  61. TPosition origPos(0, 1, request.File);
  62. TTextWalker origWalker(origPos, true);
  63. size_t i = 0;
  64. for (; i < Min(request.Program.size(), formattedQuery.size()); ++i) {
  65. if (request.Program[i] == formattedQuery[i]) {
  66. origWalker.Advance(request.Program[i]);
  67. continue;
  68. }
  69. while (i > 0 && TTextWalker::IsUtf8Intermediate(request.Program[i])) {
  70. --i;
  71. }
  72. break;
  73. }
  74. TString formattedSample = formattedQuery.substr(i, FormatContextLimit);
  75. while (!formattedSample.empty() && TTextWalker::IsUtf8Intermediate(formattedQuery.back())) {
  76. formattedSample.erase(formattedSample.size() - 1);
  77. }
  78. TString origSample = request.Program.substr(i, FormatContextLimit);
  79. while (!origSample.empty() && TTextWalker::IsUtf8Intermediate(origSample.back())) {
  80. origSample.erase(origSample.size() - 1);
  81. }
  82. res.Issues.AddIssue(TIssue(origPos, TStringBuilder() <<
  83. "Format mismatch, expected:\n" << formattedSample << "\nbut got:\n" << origSample));
  84. }
  85. return res;
  86. }
  87. };
  88. }
  89. std::unique_ptr<ICheckRunner> MakeFormatRunner() {
  90. return std::make_unique<TFormatRunner>();
  91. }
  92. }
  93. }