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