astdiff.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include <yql/essentials/utils/backtrace/backtrace.h>
  2. #include <yql/essentials/ast/yql_expr.h>
  3. #include <library/cpp/svnversion/svnversion.h>
  4. #include <util/stream/file.h>
  5. #include <util/folder/path.h>
  6. #include <util/string/split.h>
  7. #include <util/generic/yexception.h>
  8. #include <sstream>
  9. #include <contrib/libs/dtl/dtl/dtl.hpp>
  10. using namespace NYql;
  11. std::string CalculateDiff(const TString& oldAst, const TString& newAst) {
  12. auto oldLines = StringSplitter(oldAst).Split('\n').ToList<std::string>();
  13. auto newLines = StringSplitter(newAst).Split('\n').ToList<std::string>();
  14. dtl::Diff<std::string, TVector<std::string>> d(oldLines, newLines);
  15. d.compose();
  16. d.composeUnifiedHunks();
  17. std::ostringstream ss;
  18. d.printUnifiedFormat(ss);
  19. return ss.str();
  20. }
  21. const int DIFF_LINES_LIMIT = 16;
  22. void DumpSmallNodes(const TExprNode* rootOne, const TExprNode* rootTwo) {
  23. const auto isDumpSmall = [] (const TString& dump) {
  24. return std::count(dump.begin(), dump.end(), '\n') < DIFF_LINES_LIMIT;
  25. };
  26. const auto rootOneDump = rootOne->Dump();
  27. if (!isDumpSmall(rootOneDump)) {
  28. return;
  29. }
  30. const auto rootTwoDump = rootTwo->Dump();
  31. if (!isDumpSmall(rootTwoDump)) {
  32. return;
  33. }
  34. Cerr << rootOneDump << '\n' << rootTwoDump;
  35. }
  36. int Main(int argc, const char *argv[])
  37. {
  38. if (argc != 3) {
  39. PrintProgramSvnVersion();
  40. Cout << Endl << "Usage: " << argv[0] << " <fileone> <filetwo>" << Endl;
  41. return 2;
  42. }
  43. const TString fileOne(argv[1]), fileTwo(argv[2]);
  44. const TString progOneAst = TFileInput(fileOne).ReadAll();
  45. const TString progTwoAst = TFileInput(fileTwo).ReadAll();
  46. const auto progOne(ParseAst(progOneAst)), progTwo(ParseAst(progTwoAst));
  47. if (!(progOne.IsOk() && progTwo.IsOk())) {
  48. if (!progOne.IsOk()) {
  49. Cerr << "Errors in " << fileOne << Endl;
  50. progOne.Issues.PrintTo(Cerr);
  51. }
  52. if (!progTwo.IsOk()) {
  53. Cerr << "Errors in " << fileTwo << Endl;
  54. progTwo.Issues.PrintTo(Cerr);
  55. }
  56. return 3;
  57. }
  58. TExprContext ctxOne, ctxTwo;
  59. TExprNode::TPtr exprOne, exprTwo;
  60. const bool okOne = CompileExpr(*progOne.Root, exprOne, ctxOne, nullptr, nullptr);
  61. const bool okTwo = CompileExpr(*progTwo.Root, exprTwo, ctxTwo, nullptr, nullptr);
  62. if (!(okOne && okTwo)) {
  63. if (!okOne) {
  64. Cerr << "Errors on compile " << fileOne << Endl;
  65. ctxOne.IssueManager.GetIssues().PrintTo(Cerr);
  66. }
  67. if (!okTwo) {
  68. Cerr << "Errors on compile " << fileTwo << Endl;
  69. ctxTwo.IssueManager.GetIssues().PrintTo(Cerr);
  70. }
  71. return 4;
  72. }
  73. const TExprNode* rootOne = exprOne.Get();
  74. const TExprNode* rootTwo = exprTwo.Get();
  75. auto rootOnePos = ctxOne.GetPosition(rootOne->Pos());
  76. auto rootTwoPos = ctxTwo.GetPosition(rootTwo->Pos());
  77. if (!CompareExprTrees(rootOne, rootTwo)) {
  78. const auto diff = CalculateDiff(progOneAst, progTwoAst);
  79. Cerr << "Programs are not equal!" << Endl;
  80. if (rootOne->Type() != rootTwo->Type()) {
  81. Cerr << "Node in " << fileOne << " at [" << rootOnePos.Row << ":" << rootOnePos.Column << "] type is " << rootOne->Type() << Endl;
  82. Cerr << "Node in " << fileTwo << " at [" << rootTwoPos.Row << ":" << rootTwoPos.Column << "] type is " << rootTwo->Type() << Endl;
  83. Cerr << "\nFile diff:\n" << diff;
  84. } else if (rootOne->ChildrenSize() != rootTwo->ChildrenSize()) {
  85. Cerr << "Node '" << rootOne->Content() << "' in " << fileOne << " at [" << rootOnePos.Row << ":" << rootOnePos.Column << "] has " << rootOne->ChildrenSize() << " children." << Endl;
  86. Cerr << "Node '" << rootTwo->Content() << "' in " << fileTwo << " at [" << rootTwoPos.Row << ":" << rootTwoPos.Column << "] has " << rootTwo->ChildrenSize() << " children." << Endl;
  87. DumpSmallNodes(rootOne, rootTwo);
  88. Cerr << "\nFile diff:\n" << diff;
  89. } else {
  90. Cerr << "Node in " << fileOne << " at [" << rootOnePos.Row << ":" << rootOnePos.Column << "]:";
  91. Cerr << "Node in " << fileTwo << " at [" << rootTwoPos.Row << ":" << rootTwoPos.Column << "]:";
  92. DumpSmallNodes(rootOne, rootTwo);
  93. Cerr << "\nFile diff:\n" << diff;
  94. }
  95. return 5;
  96. }
  97. return 0;
  98. }
  99. int main(int argc, const char *argv[]) {
  100. NYql::NBacktrace::RegisterKikimrFatalActions();
  101. NYql::NBacktrace::EnableKikimrSymbolize();
  102. try {
  103. return Main(argc, argv);
  104. }
  105. catch (...) {
  106. Cerr << CurrentExceptionMessage() << Endl;
  107. return 1;
  108. }
  109. }