parse_hints_impl.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #include "parse_hints_impl.h"
  2. #include <yql/essentials/utils/yql_panic.h>
  3. namespace NSQLTranslation {
  4. namespace NDetail {
  5. enum EParseState {
  6. INITIAL,
  7. NAME,
  8. IN_PARENS,
  9. IN_QUOTED_VALUE,
  10. IN_VALUE,
  11. WANT_WS,
  12. };
  13. TVector<TSQLHint> ParseSqlHints(NYql::TPosition commentPos, const TStringBuf& comment, bool utf8Aware) {
  14. TVector<TSQLHint> result;
  15. if (!comment.StartsWith("/*+") && !comment.StartsWith("--+")) {
  16. return result;
  17. }
  18. TSQLHint hint;
  19. NYql::TTextWalker commentWalker(commentPos, utf8Aware);
  20. const size_t len = comment.size();
  21. EParseState state = EParseState::INITIAL;
  22. for (size_t i = 0; i < len; ++i) {
  23. auto c = comment[i];
  24. switch (state) {
  25. case EParseState::INITIAL: {
  26. if (std::isalpha(c)) {
  27. hint.Pos = commentPos;
  28. hint.Name.push_back(c);
  29. state = EParseState::NAME;
  30. }
  31. break;
  32. }
  33. case EParseState::NAME: {
  34. if (std::isalnum(c)) {
  35. hint.Name.push_back(c);
  36. } else if (c == '(') {
  37. state = EParseState::IN_PARENS;
  38. } else {
  39. hint = {};
  40. state = std::isspace(c) ? EParseState::INITIAL : EParseState::WANT_WS;
  41. }
  42. break;
  43. }
  44. case EParseState::IN_PARENS: {
  45. if (c == ')') {
  46. result.emplace_back();
  47. std::swap(hint, result.back());
  48. state = EParseState::WANT_WS;
  49. } else if (c == '\'') {
  50. hint.Values.emplace_back();
  51. state = EParseState::IN_QUOTED_VALUE;
  52. } else if (!std::isspace(c)) {
  53. hint.Values.emplace_back();
  54. hint.Values.back().push_back(c);
  55. state = EParseState::IN_VALUE;
  56. }
  57. break;
  58. }
  59. case EParseState::IN_QUOTED_VALUE: {
  60. YQL_ENSURE(!hint.Values.empty());
  61. if (c == '\'') {
  62. if (i + 1 < len && comment[i + 1] == '\'') {
  63. ++i;
  64. commentWalker.Advance(c);
  65. hint.Values.back().push_back(c);
  66. } else {
  67. state = EParseState::IN_PARENS;
  68. }
  69. } else {
  70. hint.Values.back().push_back(c);
  71. }
  72. break;
  73. }
  74. case EParseState::IN_VALUE: {
  75. if (std::isspace(c)) {
  76. state = EParseState::IN_PARENS;
  77. } else if (c == ')') {
  78. result.emplace_back();
  79. std::swap(hint, result.back());
  80. state = EParseState::WANT_WS;
  81. } else {
  82. hint.Values.back().push_back(c);
  83. }
  84. break;
  85. }
  86. case EParseState::WANT_WS: {
  87. if (std::isspace(c)) {
  88. state = EParseState::INITIAL;
  89. }
  90. break;
  91. }
  92. }
  93. commentWalker.Advance(c);
  94. }
  95. return result;
  96. }
  97. }
  98. }