libidav/davqlparser.c

changeset 82
0567444f2d76
parent 80
a2832c054c98
child 83
7d20ce5d235b
equal deleted inserted replaced
81:8e186185422c 82:0567444f2d76
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));
154 } else { 161 } else {
155 return -1; 162 return -1;
156 } 163 }
157 } 164 }
158 165
159 void dav_debug_ql_statement(DavQLStatement *stmt) { 166 void dav_debug_statement(DavQLStatement *stmt) {
160 if (!stmt) { 167 if (!stmt) {
161 fprintf(stderr, "Debug DavQLStatement failed: null pointer"); 168 fprintf(stderr, "Debug DavQLStatement failed: null pointer");
162 return; 169 return;
163 } 170 }
164 171
172 switch (cmd) { 179 switch (cmd) {
173 case DQLD_CMD_Q: return; 180 case DQLD_CMD_Q: return;
174 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; 181 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break;
175 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; 182 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break;
176 case DQLD_CMD_P: 183 case DQLD_CMD_P:
177 examineexpr = &(stmt->path); 184 examineexpr = stmt->path;
178 dav_debug_ql_expr_print(examineexpr); 185 dav_debug_ql_expr_print(examineexpr);
179 break; 186 break;
180 case DQLD_CMD_L: 187 case DQLD_CMD_L:
181 if (dav_debug_ql_expr_selected(examineexpr)) { 188 if (dav_debug_ql_expr_selected(examineexpr)) {
182 if (examineexpr->left) { 189 if (examineexpr->left) {
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 }

mercurial