hogql-parser 1.0.0__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/PKG-INFO +1 -1
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/hogql_parser.egg-info/PKG-INFO +1 -1
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/parser.cpp +54 -44
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/setup.py +1 -1
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/string.cpp +1 -1
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/HogQLLexer.cpp +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/HogQLParser.cpp +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/HogQLParserBaseVisitor.cpp +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/HogQLParserVisitor.cpp +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/README.md +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/error.cpp +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/hogql_parser.egg-info/SOURCES.txt +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/hogql_parser.egg-info/dependency_links.txt +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/hogql_parser.egg-info/top_level.txt +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/pyproject.toml +0 -0
- {hogql_parser-1.0.0 → hogql_parser-1.0.2}/setup.cfg +0 -0
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
throw NotImplementedException("Unsupported rule: " #RULE); \
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
#define HANDLE_HOGQL_EXCEPTION(TYPE)
|
|
20
|
+
#define HANDLE_HOGQL_EXCEPTION(TYPE, OTHER_CLEANUP) \
|
|
21
21
|
(const TYPE& e) { \
|
|
22
22
|
string err_what = e.what(); \
|
|
23
23
|
PyObject *error_type = NULL, *py_err_args = NULL, *py_err = NULL, *py_start = NULL, *py_end = NULL; \
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
err_indicator = PyObject_SetAttrString(py_err, "end", py_end); \
|
|
38
38
|
if (err_indicator == -1) goto exit##TYPE; \
|
|
39
39
|
PyErr_SetObject(error_type, py_err); \
|
|
40
|
-
exit##TYPE:;
|
|
40
|
+
exit##TYPE :; \
|
|
41
41
|
Py_XDECREF(py_end); \
|
|
42
42
|
Py_XDECREF(py_start); \
|
|
43
43
|
Py_XDECREF(py_err); \
|
|
44
44
|
Py_XDECREF(error_type); \
|
|
45
|
+
OTHER_CLEANUP \
|
|
45
46
|
return NULL; \
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -98,6 +99,7 @@ PyObject* X_PyList_FromStrings(const vector<string>& items) {
|
|
|
98
99
|
class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
99
100
|
private:
|
|
100
101
|
parser_state* state;
|
|
102
|
+
bool is_internal;
|
|
101
103
|
|
|
102
104
|
const vector<string> RESERVED_KEYWORDS = {"true", "false", "null", "team_id"};
|
|
103
105
|
|
|
@@ -151,7 +153,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
151
153
|
#undef IS_AST_NODE_INSTANCE_IMPL
|
|
152
154
|
|
|
153
155
|
public:
|
|
154
|
-
HogQLParseTreeConverter(parser_state* state) : state(state) {}
|
|
156
|
+
HogQLParseTreeConverter(parser_state* state, bool is_internal) : state(state), is_internal(is_internal) {}
|
|
155
157
|
|
|
156
158
|
any visit(antlr4::tree::ParseTree* tree) override {
|
|
157
159
|
// Find the start and stop indices of the parse tree node
|
|
@@ -169,17 +171,18 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
169
171
|
start = ctx->getStart()->getStartIndex();
|
|
170
172
|
stop = ctx->getStop()->getStopIndex();
|
|
171
173
|
}
|
|
172
|
-
// Visit the parse tree node
|
|
174
|
+
// Visit the parse tree node (while making sure that nodes/errors have spans - except for internal expressions)
|
|
173
175
|
any node;
|
|
174
176
|
try {
|
|
175
177
|
node = tree->accept(this);
|
|
176
178
|
} catch (const SyntaxException& e) {
|
|
177
|
-
|
|
179
|
+
// If start and end are unset, rethrow with the current start and stop
|
|
180
|
+
if (!is_internal && e.start == 0 && e.end == 0) {
|
|
178
181
|
throw SyntaxException(e.what(), start, stop + 1);
|
|
179
182
|
}
|
|
180
183
|
throw;
|
|
181
184
|
}
|
|
182
|
-
if (node.has_value() && node.type() == typeid(PyObject*)) {
|
|
185
|
+
if (!is_internal && node.has_value() && node.type() == typeid(PyObject*)) {
|
|
183
186
|
PyObject* py_node = any_cast<PyObject*>(node);
|
|
184
187
|
if (py_node) {
|
|
185
188
|
int is_ast = is_ast_node_instance(py_node);
|
|
@@ -218,8 +221,9 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
218
221
|
PyObject* visitAsPyObjectFinal(antlr4::tree::ParseTree* tree) {
|
|
219
222
|
try {
|
|
220
223
|
return visitAsPyObject(tree);
|
|
221
|
-
} catch HANDLE_HOGQL_EXCEPTION(SyntaxException) catch HANDLE_HOGQL_EXCEPTION(
|
|
222
|
-
|
|
224
|
+
} catch HANDLE_HOGQL_EXCEPTION(SyntaxException, ) catch HANDLE_HOGQL_EXCEPTION(
|
|
225
|
+
NotImplementedException,
|
|
226
|
+
) catch HANDLE_HOGQL_EXCEPTION(ParsingException, ) catch (const PyInternalException& e) {
|
|
223
227
|
return NULL;
|
|
224
228
|
} catch (const bad_any_cast& e) {
|
|
225
229
|
PyObject* error_type = PyObject_GetAttrString(state->errors_module, "ParsingException");
|
|
@@ -1789,7 +1793,8 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
1789
1793
|
VISIT(TableFunctionExpr) {
|
|
1790
1794
|
string table_name = visitAsString(ctx->identifier());
|
|
1791
1795
|
auto table_args_ctx = ctx->tableArgList();
|
|
1792
|
-
PyObject* table_args = table_args_ctx ? visitAsPyObject(table_args_ctx) :
|
|
1796
|
+
PyObject* table_args = table_args_ctx ? visitAsPyObject(table_args_ctx) : PyList_New(0);
|
|
1797
|
+
if (!table_args) throw PyInternalException();
|
|
1793
1798
|
PyObject* table = build_ast_node("Field", "{s:[s#]}", "chain", table_name.data(), table_name.size());
|
|
1794
1799
|
if (!table) {
|
|
1795
1800
|
Py_DECREF(table_args);
|
|
@@ -2030,32 +2035,35 @@ parser_state* get_module_state(PyObject* module) {
|
|
|
2030
2035
|
|
|
2031
2036
|
// MODULE METHODS
|
|
2032
2037
|
|
|
2033
|
-
#define METHOD_PARSE_NODE(PASCAL_CASE, CAMEL_CASE, SNAKE_CASE)
|
|
2034
|
-
static PyObject* method_parse_##SNAKE_CASE(PyObject* self, PyObject* args) {
|
|
2035
|
-
parser_state* state = get_module_state(self);
|
|
2036
|
-
const char* str;
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
auto
|
|
2043
|
-
auto
|
|
2044
|
-
|
|
2045
|
-
auto
|
|
2046
|
-
parser->
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
delete
|
|
2057
|
-
delete
|
|
2058
|
-
|
|
2038
|
+
#define METHOD_PARSE_NODE(PASCAL_CASE, CAMEL_CASE, SNAKE_CASE) \
|
|
2039
|
+
static PyObject* method_parse_##SNAKE_CASE(PyObject* self, PyObject* args, PyObject* kwargs) { \
|
|
2040
|
+
parser_state* state = get_module_state(self); \
|
|
2041
|
+
const char* str; \
|
|
2042
|
+
int internal = 0; \
|
|
2043
|
+
static const char* kwlist[] = {"input", "is_internal", NULL}; \
|
|
2044
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|p", (char**)kwlist, &str, &internal)) { \
|
|
2045
|
+
return NULL; \
|
|
2046
|
+
} \
|
|
2047
|
+
auto input_stream = new antlr4::ANTLRInputStream(str, strnlen(str, 65536)); \
|
|
2048
|
+
auto lexer = new HogQLLexer(input_stream); \
|
|
2049
|
+
auto stream = new antlr4::CommonTokenStream(lexer); \
|
|
2050
|
+
auto parser = new HogQLParser(stream); \
|
|
2051
|
+
parser->removeErrorListeners(); \
|
|
2052
|
+
auto error_listener = new HogQLErrorListener(str); \
|
|
2053
|
+
parser->addErrorListener(error_listener); \
|
|
2054
|
+
HogQLParser::PASCAL_CASE##Context* parse_tree; \
|
|
2055
|
+
try { \
|
|
2056
|
+
parse_tree = parser->CAMEL_CASE(); \
|
|
2057
|
+
} catch HANDLE_HOGQL_EXCEPTION(SyntaxException, delete error_listener; delete parser; delete stream; delete lexer; \
|
|
2058
|
+
delete input_stream;); \
|
|
2059
|
+
HogQLParseTreeConverter converter = HogQLParseTreeConverter(state, internal == 1); \
|
|
2060
|
+
PyObject* result_node = converter.visitAsPyObjectFinal(parse_tree); \
|
|
2061
|
+
delete error_listener; \
|
|
2062
|
+
delete parser; \
|
|
2063
|
+
delete stream; \
|
|
2064
|
+
delete lexer; \
|
|
2065
|
+
delete input_stream; \
|
|
2066
|
+
return result_node; \
|
|
2059
2067
|
}
|
|
2060
2068
|
|
|
2061
2069
|
METHOD_PARSE_NODE(Expr, expr, expr)
|
|
@@ -2073,7 +2081,7 @@ static PyObject* method_unquote_string(PyObject* self, PyObject* args) {
|
|
|
2073
2081
|
string unquoted_string;
|
|
2074
2082
|
try {
|
|
2075
2083
|
unquoted_string = unquote_string(str);
|
|
2076
|
-
} catch HANDLE_HOGQL_EXCEPTION(SyntaxException);
|
|
2084
|
+
} catch HANDLE_HOGQL_EXCEPTION(SyntaxException, );
|
|
2077
2085
|
return PyUnicode_FromStringAndSize(unquoted_string.data(), unquoted_string.size());
|
|
2078
2086
|
}
|
|
2079
2087
|
|
|
@@ -2081,22 +2089,23 @@ static PyObject* method_unquote_string(PyObject* self, PyObject* args) {
|
|
|
2081
2089
|
|
|
2082
2090
|
static PyMethodDef parser_methods[] = {
|
|
2083
2091
|
{.ml_name = "parse_expr",
|
|
2084
|
-
.ml_meth = method_parse_expr,
|
|
2085
|
-
.ml_flags = METH_VARARGS,
|
|
2092
|
+
.ml_meth = (PyCFunction)method_parse_expr,
|
|
2093
|
+
.ml_flags = METH_VARARGS | METH_KEYWORDS,
|
|
2086
2094
|
.ml_doc = "Parse the HogQL expression string into an AST"},
|
|
2087
2095
|
{.ml_name = "parse_order_expr",
|
|
2088
|
-
.ml_meth = method_parse_order_expr,
|
|
2089
|
-
.ml_flags = METH_VARARGS,
|
|
2096
|
+
.ml_meth = (PyCFunction)method_parse_order_expr,
|
|
2097
|
+
.ml_flags = METH_VARARGS | METH_KEYWORDS,
|
|
2090
2098
|
.ml_doc = "Parse the ORDER BY clause string into an AST"},
|
|
2091
2099
|
{.ml_name = "parse_select",
|
|
2092
|
-
.ml_meth = method_parse_select,
|
|
2093
|
-
.ml_flags = METH_VARARGS,
|
|
2100
|
+
.ml_meth = (PyCFunction)method_parse_select,
|
|
2101
|
+
.ml_flags = METH_VARARGS | METH_KEYWORDS,
|
|
2094
2102
|
.ml_doc = "Parse the HogQL SELECT statement string into an AST"},
|
|
2095
2103
|
{.ml_name = "unquote_string",
|
|
2096
2104
|
.ml_meth = method_unquote_string,
|
|
2097
2105
|
.ml_flags = METH_VARARGS,
|
|
2098
2106
|
.ml_doc = "Unquote the string (an identifier or a string literal))"},
|
|
2099
|
-
{NULL, NULL, 0, NULL}
|
|
2107
|
+
{NULL, NULL, 0, NULL}
|
|
2108
|
+
};
|
|
2100
2109
|
|
|
2101
2110
|
static int parser_modexec(PyObject* module) {
|
|
2102
2111
|
parser_state* state = get_module_state(module);
|
|
@@ -2118,7 +2127,8 @@ static int parser_modexec(PyObject* module) {
|
|
|
2118
2127
|
static PyModuleDef_Slot parser_slots[] = {
|
|
2119
2128
|
{Py_mod_exec, (void*)parser_modexec}, // If Python were written in C++, then Py_mod_exec would be typed better, but
|
|
2120
2129
|
// because it's in C, it expects a void pointer
|
|
2121
|
-
{0, NULL}
|
|
2130
|
+
{0, NULL}
|
|
2131
|
+
};
|
|
2122
2132
|
|
|
2123
2133
|
static int parser_traverse(PyObject* module, visitproc visit, void* arg) {
|
|
2124
2134
|
parser_state* state = get_module_state(module);
|
|
@@ -40,7 +40,7 @@ string unquote_string(string text) {
|
|
|
40
40
|
boost::replace_all(text, "\\r", "\r");
|
|
41
41
|
boost::replace_all(text, "\\t", "\t");
|
|
42
42
|
boost::replace_all(text, "\\v", "\v");
|
|
43
|
-
boost::replace_all(text, "\\0", "");
|
|
43
|
+
boost::replace_all(text, "\\0", ""); // NUL characters are ignored
|
|
44
44
|
boost::replace_all(text, "\\\\", "\\");
|
|
45
45
|
|
|
46
46
|
return text;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|