27 */ |
27 */ |
28 |
28 |
29 #include "davqlparser.h" |
29 #include "davqlparser.h" |
30 #include <string.h> |
30 #include <string.h> |
31 #include <stdio.h> |
31 #include <stdio.h> |
|
32 #include <ctype.h> |
32 |
33 |
33 #define sfmtarg(s) ((int)(s).length), (s).ptr |
34 #define sfmtarg(s) ((int)(s).length), (s).ptr |
|
35 |
|
36 // ------------------------------------------------------------------------ |
|
37 // D E B U G E R |
|
38 // ------------------------------------------------------------------------ |
34 |
39 |
35 static const char* _map_querytype(davqltype_t type) { |
40 static const char* _map_querytype(davqltype_t type) { |
36 switch(type) { |
41 switch(type) { |
37 case GET: return "GET"; |
42 case DAVQL_ERROR: return "ERROR"; |
38 case SET: return "SET"; |
43 case DAVQL_GET: return "GET"; |
|
44 case DAVQL_SET: return "SET"; |
39 default: return "unknown"; |
45 default: return "unknown"; |
40 } |
46 } |
41 } |
47 } |
42 |
48 |
43 static const char* _map_exprtype(davqlexprtype_t type) { |
49 static const char* _map_exprtype(davqlexprtype_t type) { |
44 switch(type) { |
50 switch(type) { |
45 case LITERAL: return "LITERAL"; |
51 case DAVQL_LITERAL: return "LITERAL"; |
46 case IDENTIFIER: return "IDENTIFIER"; |
52 case DAVQL_IDENTIFIER: return "IDENTIFIER"; |
47 case UNARY: return "UNARY"; |
53 case DAVQL_UNARY: return "UNARY"; |
48 case BINARY: return "BINARY"; |
54 case DAVQL_BINARY: return "BINARY"; |
49 case LOGICAL: return "LOGICAL"; |
55 case DAVQL_LOGICAL: return "LOGICAL"; |
50 case FUNCCALL: return "FUNCCALL"; |
56 case DAVQL_FUNCCALL: return "FUNCCALL"; |
51 default: return "unknown"; |
57 default: return "unknown"; |
52 } |
58 } |
53 } |
59 } |
54 |
60 |
55 static const char* _map_operator(davqloperator_t op) { |
61 static const char* _map_operator(davqloperator_t op) { |
65 default: return "unknown"; |
71 default: return "unknown"; |
66 } |
72 } |
67 } |
73 } |
68 |
74 |
69 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { |
75 static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { |
|
76 sstr_t empty = ST("(empty)"); |
70 |
77 |
71 // Basic information |
78 // Basic information |
72 printf("Statement: %*s\nType: %s\nField count: %zu", |
79 printf("Statement: %.*s\nType: %s\nField count: %zu", |
73 sfmtarg(stmt->srctext), |
80 sfmtarg(stmt->srctext), |
74 _map_querytype(stmt->type), |
81 _map_querytype(stmt->type), |
75 ucx_list_size(stmt->fields)); |
82 ucx_list_size(stmt->fields)); |
76 |
83 |
77 // Has wildcard |
84 // Has wildcard |
78 _Bool wildcard = 0; |
85 _Bool wildcard = 0; |
79 UCX_FOREACH(elm, stmt->fields) { |
86 UCX_FOREACH(elm, stmt->fields) { |
80 DavQLExpression* expr = (DavQLExpression*)elm->data; |
87 DavQLExpression* expr = (DavQLExpression*)elm->data; |
81 if (expr->type == IDENTIFIER && |
88 if (expr->type == DAVQL_IDENTIFIER && |
82 expr->srctext.length == 1 && *(expr->srctext.ptr) == '*') { |
89 expr->srctext.length == 1 && *(expr->srctext.ptr) == '*') { |
83 wildcard = 1; |
90 wildcard = 1; |
84 } |
91 } |
85 } |
92 } |
86 printf(" %s wildcard\nPath: %*s\nHas where clause: %s\n", |
93 printf(" %s wildcard\nPath: %.*s\nHas where clause: %s\n", |
87 wildcard?"with":"without", |
94 wildcard?"with":"without", |
88 sfmtarg(stmt->path.srctext), |
95 sfmtarg(stmt->path ? stmt->path->srctext : empty), |
89 stmt->where ? "yes" : "no"); |
96 stmt->where ? "yes" : "no"); |
90 if (stmt->type == SET) { |
97 if (stmt->type == DAVQL_SET) { |
91 printf("Value list size matches: %s", |
98 printf("Value list size matches: %s", |
92 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) |
99 ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) |
93 ? "yes" : "no"); |
100 ? "yes" : "no"); |
94 } |
101 } |
95 |
102 |
110 } |
117 } |
111 } |
118 } |
112 |
119 |
113 static void dav_debug_ql_expr_print(DavQLExpression *expr) { |
120 static void dav_debug_ql_expr_print(DavQLExpression *expr) { |
114 if (dav_debug_ql_expr_selected(expr)) { |
121 if (dav_debug_ql_expr_selected(expr)) { |
115 sstr_t empty = S("(empty)"); |
122 sstr_t empty = ST("(empty)"); |
116 printf( |
123 printf( |
117 "Text: %*s\nType: %s\nOperator: %s\n" |
124 "Text: %.*s\nType: %s\nOperator: %s\n" |
118 "Left hand: %*s\nRight hand: %*s\n", |
125 "Left hand: %.*s\nRight hand: %.*s\n", |
119 sfmtarg(expr->srctext), |
126 sfmtarg(expr->srctext), |
120 _map_exprtype(expr->type), |
127 _map_exprtype(expr->type), |
121 _map_operator(expr->op), |
128 _map_operator(expr->op), |
122 sfmtarg(expr->left?expr->left->srctext:empty), |
129 sfmtarg(expr->left?expr->left->srctext:empty), |
123 sfmtarg(expr->right?expr->right->srctext:empty)); |
130 sfmtarg(expr->right?expr->right->srctext:empty)); |
211 default: printf("unknown command\n"); |
218 default: printf("unknown command\n"); |
212 } |
219 } |
213 } |
220 } |
214 } |
221 } |
215 |
222 |
|
223 // ------------------------------------------------------------------------ |
|
224 // P A R S E R |
|
225 // ------------------------------------------------------------------------ |
|
226 |
|
227 static UcxList* dav_parse_tokenize(sstr_t src) { |
|
228 UcxList *tokens = NULL; |
|
229 |
|
230 // Delimiters: whitespace and dead whitespace around commas |
|
231 sstr_t *token = NULL; |
|
232 for (size_t i = 0 ; i < src.length ; i++) { |
|
233 if (isspace(src.ptr[i])) { |
|
234 // add token before spaces to list (if any) |
|
235 if (token) { |
|
236 tokens = ucx_list_append(tokens, token); |
|
237 token = NULL; |
|
238 } |
|
239 } else if (src.ptr[i] == ',') { |
|
240 // add token before comma to list (if any) |
|
241 if (token) { |
|
242 tokens = ucx_list_append(tokens, token); |
|
243 token = NULL; |
|
244 } |
|
245 // add comma as token to list |
|
246 token = malloc(sizeof(sstr_t)); |
|
247 token->ptr = src.ptr + i; |
|
248 token->length = 1; |
|
249 tokens = ucx_list_append(tokens, token); |
|
250 // set tokenizer ready to read more tokens |
|
251 token = NULL; |
|
252 } else { |
|
253 // if this is a new token, create memory for it |
|
254 if (!token) { |
|
255 token = malloc(sizeof(sstr_t)); |
|
256 token->ptr = src.ptr + i; |
|
257 token->length = 0; |
|
258 } |
|
259 // extend token length when reading more bytes |
|
260 token->length++; |
|
261 } |
|
262 } |
|
263 |
|
264 if (token) { |
|
265 tokens = ucx_list_append(tokens, token); |
|
266 } |
|
267 |
|
268 return tokens; |
|
269 } |
|
270 |
|
271 static DavQLExpression* dav_parse_expression(sstr_t src) { |
|
272 DavQLExpression *expr = calloc(1, sizeof(DavQLExpression)); |
|
273 expr->srctext = src; |
|
274 |
|
275 return expr; |
|
276 } |
|
277 |
|
278 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { |
|
279 stmt->type = DAVQL_GET; |
|
280 |
|
281 /* |
|
282 * 10: field list |
|
283 * 20: FROM clause |
|
284 * 520: expecting WHERE or WITH clause |
|
285 * 30: WHERE clause |
|
286 * 530: expecting WITH clause |
|
287 * 40: WITH clause |
|
288 * 500: ready to quit |
|
289 * |
|
290 */ |
|
291 int step = 10; |
|
292 |
|
293 UCX_FOREACH(token, tokens) { |
|
294 sstr_t tokendata = *(sstr_t*)token->data; |
|
295 |
|
296 switch (step) { |
|
297 // optional clauses |
|
298 case 520: |
|
299 if (!sstrcasecmp(tokendata, S("where"))) { |
|
300 step = 30; |
|
301 } |
|
302 /* no break */ |
|
303 case 530: |
|
304 if (!sstrcasecmp(tokendata, S("with"))) { |
|
305 step = 40; |
|
306 } |
|
307 break; |
|
308 // field list |
|
309 case 10: |
|
310 if (!sstrcasecmp(tokendata, S("from"))) { |
|
311 step = 20; |
|
312 } else { |
|
313 stmt->fields = ucx_list_append(stmt->fields, |
|
314 dav_parse_expression(tokendata)); |
|
315 } |
|
316 break; |
|
317 // from clause |
|
318 case 20: |
|
319 stmt->path = dav_parse_expression(tokendata); |
|
320 step = 520; |
|
321 break; |
|
322 // where clause |
|
323 case 30: |
|
324 step = 530; |
|
325 break; |
|
326 // with clause |
|
327 case 40: |
|
328 step = 500; |
|
329 break; |
|
330 } |
|
331 |
|
332 free(token->data); |
|
333 } |
|
334 |
|
335 if (step < 500) { |
|
336 stmt->type = DAVQL_ERROR; |
|
337 // TODO: save parse error message |
|
338 } |
|
339 } |
|
340 |
|
341 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { |
|
342 stmt->type = DAVQL_SET; |
|
343 |
|
344 UCX_FOREACH(token, tokens) { |
|
345 sstr_t tokendata = *(sstr_t*)token->data; |
|
346 |
|
347 // just free the tokens, until the function is implemented |
|
348 |
|
349 free(token->data); |
|
350 } |
|
351 } |
|
352 |
216 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
353 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
217 DavQLStatement *stmt = malloc(sizeof(DavQLStatement)); |
354 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
218 |
355 |
219 // default values |
356 // default values |
220 memset(stmt, 0, sizeof(DavQLStatement)); |
357 stmt->type = -1; |
221 stmt->srctext = srctext; |
|
222 stmt->type = stmt->path.type = stmt->path.op = -1; |
|
223 stmt->depth = SIZE_MAX; |
358 stmt->depth = SIZE_MAX; |
224 |
359 |
|
360 // save trimmed source text |
|
361 stmt->srctext = sstrtrim(srctext); |
|
362 |
|
363 // tokenization |
|
364 UcxList* tokens = dav_parse_tokenize(stmt->srctext); |
|
365 |
|
366 // use first token to determine query type |
|
367 if (tokens) { |
|
368 sstr_t token = *(sstr_t*)tokens->data; |
|
369 free(tokens->data); |
|
370 tokens = ucx_list_remove(tokens, tokens); |
|
371 if (!sstrcasecmp(token, S("get"))) { |
|
372 dav_parse_get_statement(stmt, tokens); |
|
373 } else if (!sstrcasecmp(token, S("set"))) { |
|
374 dav_parse_set_statement(stmt, tokens); |
|
375 } else { |
|
376 stmt->type = DAVQL_ERROR; |
|
377 } |
|
378 ucx_list_free(tokens); |
|
379 } else { |
|
380 stmt->type = DAVQL_ERROR; |
|
381 } |
225 |
382 |
226 return stmt; |
383 return stmt; |
227 } |
384 } |
|
385 |
|
386 static void dav_free_expression(DavQLExpression *expr) { |
|
387 if (expr->left) { |
|
388 dav_free_expression(expr->left); |
|
389 } |
|
390 if (expr->right) { |
|
391 dav_free_expression(expr->right); |
|
392 } |
|
393 free(expr); |
|
394 } |
|
395 |
|
396 void dav_free_statement(DavQLStatement *stmt) { |
|
397 UCX_FOREACH(expr, stmt->fields) { |
|
398 dav_free_expression(expr->data); |
|
399 } |
|
400 ucx_list_free(stmt->fields); |
|
401 UCX_FOREACH(expr, stmt->setvalues) { |
|
402 dav_free_expression(expr->data); |
|
403 } |
|
404 ucx_list_free(stmt->setvalues); |
|
405 |
|
406 if (stmt->path) { |
|
407 dav_free_expression(stmt->path); |
|
408 } |
|
409 if (stmt->where) { |
|
410 dav_free_expression(stmt->where); |
|
411 } |
|
412 free(stmt); |
|
413 } |