1#pragma once
2
3#include <set>
4#include <memory>
5
6#include <Core/Defines.h>
7#include <Core/Types.h>
8#include <Parsers/IAST.h>
9#include <Parsers/TokenIterator.h>
10
11
12namespace DB
13{
14
15namespace ErrorCodes
16{
17 extern const int TOO_DEEP_RECURSION;
18 extern const int LOGICAL_ERROR;
19}
20
21
22/** Collects variants, how parser could proceed further at rightmost position.
23 */
24struct Expected
25{
26 const char * max_parsed_pos = nullptr;
27 std::set<const char *> variants;
28
29 /// 'description' should be statically allocated string.
30 void add(const char * current_pos, const char * description)
31 {
32 if (!max_parsed_pos || current_pos > max_parsed_pos)
33 {
34 variants.clear();
35 max_parsed_pos = current_pos;
36 }
37
38 if (!max_parsed_pos || current_pos >= max_parsed_pos)
39 variants.insert(description);
40 }
41
42 void add(TokenIterator it, const char * description)
43 {
44 add(it->begin, description);
45 }
46};
47
48
49/** Interface for parser classes
50 */
51class IParser
52{
53public:
54 /// Token iterator augmented with depth information. This allows to control recursion depth.
55 struct Pos : TokenIterator
56 {
57 using TokenIterator::TokenIterator;
58
59 uint32_t depth = 0;
60 uint32_t max_depth = 1000;
61
62 void increaseDepth()
63 {
64 ++depth;
65 if (depth > max_depth)
66 throw Exception("Maximum parse depth exceeded", ErrorCodes::TOO_DEEP_RECURSION);
67 }
68
69 void decreaseDepth()
70 {
71 if (depth == 0)
72 throw Exception("Logical error in parser: incorrect calculation of parse depth", ErrorCodes::LOGICAL_ERROR);
73 --depth;
74 }
75 };
76
77 /** Get the text of this parser parses. */
78 virtual const char * getName() const = 0;
79
80 /** Parse piece of text from position `pos`, but not beyond end of line (`end` - position after end of line),
81 * move pointer `pos` to the maximum position to which it was possible to parse,
82 * in case of success return `true` and the result in `node` if it is needed, otherwise false,
83 * in `expected` write what was expected in the maximum position,
84 * to which it was possible to parse if parsing was unsuccessful,
85 * or what this parser parse if parsing was successful.
86 * The string to which the [begin, end) range is included may be not 0-terminated.
87 */
88 virtual bool parse(Pos & pos, ASTPtr & node, Expected & expected) = 0;
89
90 bool ignore(Pos & pos, Expected & expected)
91 {
92 ASTPtr ignore_node;
93 return parse(pos, ignore_node, expected);
94 }
95
96 bool ignore(Pos & pos)
97 {
98 Expected expected;
99 return ignore(pos, expected);
100 }
101
102 /** The same, but do not move the position and do not write the result to node.
103 */
104 bool check(Pos & pos, Expected & expected)
105 {
106 Pos begin = pos;
107 ASTPtr node;
108 if (!parse(pos, node, expected))
109 {
110 pos = begin;
111 return false;
112 }
113 else
114 return true;
115 }
116
117 /** The same, but doesn't move the position even if parsing was successful.
118 */
119 bool checkWithoutMoving(Pos pos, Expected & expected)
120 {
121 ASTPtr node;
122 return parse(pos, node, expected);
123 }
124
125 virtual ~IParser() {}
126};
127
128using ParserPtr = std::unique_ptr<IParser>;
129
130}
131