180 sfmtarg(expr->right?expr->right->srctext:empty)); |
180 sfmtarg(expr->right?expr->right->srctext:empty)); |
181 } |
181 } |
182 } |
182 } |
183 } |
183 } |
184 |
184 |
|
185 static void dav_debug_ql_field_print(DavQLField *field) { |
|
186 if (field) { |
|
187 printf("Name: %.*s\n", sfmtarg(field->name)); |
|
188 if (field->expr) { |
|
189 dav_debug_ql_expr_print(field->expr); |
|
190 } else { |
|
191 printf("No expression.\n"); |
|
192 } |
|
193 } else { |
|
194 printf("No field selected.\n"); |
|
195 } |
|
196 } |
|
197 |
185 static void dav_debug_ql_tree_print(DavQLExpression *expr, int depth) { |
198 static void dav_debug_ql_tree_print(DavQLExpression *expr, int depth) { |
186 if (expr) { |
199 if (expr) { |
187 if (expr->left) { |
200 if (expr->left) { |
188 printf("%*c%s\n", depth, ' ', _map_operator(expr->op)); |
201 printf("%*c%s\n", depth, ' ', _map_operator(expr->op)); |
189 dav_debug_ql_tree_print(expr->left, depth+1); |
202 dav_debug_ql_tree_print(expr->left, depth+1); |
277 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; |
290 case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; |
278 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; |
291 case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; |
279 case DQLD_CMD_PT: dav_debug_ql_tree_print(examineexpr, 1); break; |
292 case DQLD_CMD_PT: dav_debug_ql_tree_print(examineexpr, 1); break; |
280 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break; |
293 case DQLD_CMD_PF: dav_debug_ql_fnames_print(stmt); break; |
281 case DQLD_CMD_F: |
294 case DQLD_CMD_F: |
282 if (examineclause != DQLD_CMD_F) { |
295 examineclause = DQLD_CMD_F; |
283 examineclause = DQLD_CMD_F; |
296 examineelem = stmt->fields; |
284 examineelem = stmt->fields; |
297 if (stmt->fields) { |
285 examineexpr = stmt->fields ? |
298 DavQLField* field = ((DavQLField*)stmt->fields->data); |
286 ((DavQLField*)stmt->fields->data)->expr : NULL; |
299 examineexpr = field->expr; |
287 dav_debug_ql_expr_print(examineexpr); |
300 dav_debug_ql_field_print(field); |
|
301 } else { |
|
302 examineexpr = NULL; |
288 } |
303 } |
289 break; |
304 break; |
290 case DQLD_CMD_W: |
305 case DQLD_CMD_W: |
291 examineclause = 0; examineelem = NULL; |
306 examineclause = 0; examineelem = NULL; |
292 examineexpr = stmt->where; |
307 examineexpr = stmt->where; |
293 dav_debug_ql_expr_print(examineexpr); |
308 dav_debug_ql_expr_print(examineexpr); |
294 break; |
309 break; |
295 case DQLD_CMD_O: |
310 case DQLD_CMD_O: |
296 if (examineclause != DQLD_CMD_O) { |
311 examineclause = DQLD_CMD_O; |
297 examineclause = DQLD_CMD_O; |
312 examineelem = stmt->orderby; |
298 examineelem = stmt->orderby; |
313 examineexpr = stmt->orderby ? |
299 examineexpr = stmt->orderby ? |
314 ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; |
300 ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; |
315 dav_debug_ql_expr_print(examineexpr); |
301 dav_debug_ql_expr_print(examineexpr); |
|
302 } |
|
303 break; |
316 break; |
304 case DQLD_CMD_N: |
317 case DQLD_CMD_N: |
305 case DQLD_CMD_P: |
318 case DQLD_CMD_P: |
306 if (examineelem) { |
319 if (examineelem) { |
307 UcxList *newelem = (cmd == DQLD_CMD_N ? |
320 UcxList *newelem = (cmd == DQLD_CMD_N ? |
309 if (newelem) { |
322 if (newelem) { |
310 examineelem = newelem; |
323 examineelem = newelem; |
311 if (examineclause == DQLD_CMD_O) { |
324 if (examineclause == DQLD_CMD_O) { |
312 examineexpr = ((DavQLOrderCriterion*) |
325 examineexpr = ((DavQLOrderCriterion*) |
313 examineelem->data)->column; |
326 examineelem->data)->column; |
|
327 dav_debug_ql_expr_print(examineexpr); |
314 } else if (examineclause == DQLD_CMD_F) { |
328 } else if (examineclause == DQLD_CMD_F) { |
315 examineexpr = ((DavQLField*)examineelem->data)->expr; |
329 DavQLField* field = (DavQLField*)examineelem->data; |
|
330 examineexpr = field->expr; |
|
331 dav_debug_ql_field_print(field); |
316 } else { |
332 } else { |
317 printf("Examining unknown clause type."); |
333 printf("Examining unknown clause type."); |
318 } |
334 } |
319 dav_debug_ql_expr_print(examineexpr); |
|
320 } else { |
335 } else { |
321 printf("Reached end of list.\n"); |
336 printf("Reached end of list.\n"); |
322 } |
337 } |
323 } else { |
338 } else { |
324 printf("Currently not examining an expression list.\n"); |
339 printf("Currently not examining an expression list.\n"); |
377 #define _error_out_of_memory "out of memory" |
392 #define _error_out_of_memory "out of memory" |
378 #define _error_unexpected_token "unexpected token " _error_context |
393 #define _error_unexpected_token "unexpected token " _error_context |
379 #define _error_invalid_token "invalid token " _error_context |
394 #define _error_invalid_token "invalid token " _error_context |
380 #define _error_missing_path "expected path " _error_context |
395 #define _error_missing_path "expected path " _error_context |
381 #define _error_missing_from "expecting FROM keyword " _error_context |
396 #define _error_missing_from "expecting FROM keyword " _error_context |
|
397 #define _error_missing_at "expecting AT keyword " _error_context |
382 #define _error_missing_by "expecting BY keyword " _error_context |
398 #define _error_missing_by "expecting BY keyword " _error_context |
383 #define _error_missing_as "expecting alias ('as <identifier>') " _error_context |
399 #define _error_missing_as "expecting alias ('as <identifier>') " _error_context |
384 #define _error_missing_identifier "expecting identifier " _error_context |
400 #define _error_missing_identifier "expecting identifier " _error_context |
385 #define _error_missing_par "missing closed parenthesis " _error_context |
401 #define _error_missing_par "missing closed parenthesis " _error_context |
|
402 #define _error_missing_assign "expecting assignment ('=') " _error_context |
|
403 #define _error_missing_where "SET statements must have a WHERE clause or " \ |
|
404 "explicitly use ANYWHERE " _error_context |
386 #define _error_invalid_depth "invalid depth " _error_context |
405 #define _error_invalid_depth "invalid depth " _error_context |
387 #define _error_missing_expr "missing expression " _error_context |
406 #define _error_missing_expr "missing expression " _error_context |
388 #define _error_invalid_expr "invalid expression " _error_context |
407 #define _error_invalid_expr "invalid expression " _error_context |
389 #define _error_invalid_unary_op "invalid unary operator " _error_context |
408 #define _error_invalid_unary_op "invalid unary operator " _error_context |
390 #define _error_invalid_logical_op "invalid logical operator " _error_context |
409 #define _error_invalid_logical_op "invalid logical operator " _error_context |
1460 } while (consumed); |
1479 } while (consumed); |
1461 |
1480 |
1462 return total_consumed; |
1481 return total_consumed; |
1463 } |
1482 } |
1464 |
1483 |
|
1484 |
|
1485 static int dav_parse_assignments(DavQLStatement *stmt, UcxList *token) { |
|
1486 |
|
1487 // RULE: Assignment, {",", Assignment} |
|
1488 int total_consumed = 0, consumed; |
|
1489 do { |
|
1490 // RULE: Identifier, "=", Expression |
|
1491 if (token_is(token, DAVQL_TOKEN_IDENTIFIER)) { |
|
1492 |
|
1493 // Identifier |
|
1494 DavQLField *field; |
|
1495 dqlsec_malloc(stmt, field, DavQLField); |
|
1496 field->name = token_sstr(token); |
|
1497 total_consumed++; |
|
1498 token = token->next; |
|
1499 |
|
1500 // "=" |
|
1501 if (!token_is(token, DAVQL_TOKEN_OPERATOR) |
|
1502 || !tokenvalue_is(token, "=")) { |
|
1503 dav_free_field(field); |
|
1504 |
|
1505 dav_error_in_context(DAVQL_ERROR_MISSING_ASSIGN, |
|
1506 _error_missing_assign, stmt, token); |
|
1507 return total_consumed; |
|
1508 } |
|
1509 total_consumed++; |
|
1510 token = token->next; |
|
1511 |
|
1512 // Expression |
|
1513 dqlsec_mallocz(stmt, field->expr, DavQLExpression); |
|
1514 consumed = dav_parse_expression(stmt, token, field->expr); |
|
1515 if (stmt->errorcode) { |
|
1516 dav_free_field(field); |
|
1517 return total_consumed; |
|
1518 } |
|
1519 token = ucx_list_get(token, consumed); |
|
1520 total_consumed += consumed; |
|
1521 |
|
1522 // Add assignment to list and check if there's another one |
|
1523 dqlsec_list_append_or_free(stmt, stmt->fields, field); |
|
1524 consumed = token_is(token, DAVQL_TOKEN_COMMA) ? 1 : 0; |
|
1525 if (consumed) { |
|
1526 token = token->next; |
|
1527 total_consumed++; |
|
1528 } |
|
1529 } else { |
|
1530 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1531 _error_missing_identifier, stmt, token); |
|
1532 return total_consumed; |
|
1533 } |
|
1534 } while (consumed); |
|
1535 |
|
1536 return total_consumed; |
|
1537 } |
|
1538 |
|
1539 static int dav_parse_path(DavQLStatement *stmt, UcxList *tokens) { |
|
1540 if (token_is(tokens, DAVQL_TOKEN_STRING)) { |
|
1541 stmt->path = token_sstr(tokens); |
|
1542 tokens = tokens->next; |
|
1543 return 1; |
|
1544 } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) |
|
1545 && tokenvalue_is(tokens, "/")) { |
|
1546 stmt->path = token_sstr(tokens); |
|
1547 tokens = tokens->next; |
|
1548 int consumed = 1; |
|
1549 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && |
|
1550 !token_is(tokens, DAVQL_TOKEN_END)) { |
|
1551 sstr_t toksstr = token_sstr(tokens); |
|
1552 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; |
|
1553 tokens = tokens->next; |
|
1554 consumed++; |
|
1555 } |
|
1556 return consumed; |
|
1557 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && |
|
1558 tokenvalue_is(tokens, "%s")) { |
|
1559 stmt->path = token_sstr(tokens); |
|
1560 tokens = tokens->next; |
|
1561 return 1; |
|
1562 } else { |
|
1563 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1564 _error_missing_path, stmt, tokens); |
|
1565 return 0; |
|
1566 } |
|
1567 } |
|
1568 |
1465 /** |
1569 /** |
1466 * Parser of a select statement. |
1570 * Parser of a select statement. |
1467 * @param stmt the statement object that shall contain the syntax tree |
1571 * @param stmt the statement object that shall contain the syntax tree |
1468 * @param tokens the token list |
1572 * @param tokens the token list |
1469 */ |
1573 */ |
1474 tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); |
1578 tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); |
1475 if (stmt->errorcode) { |
1579 if (stmt->errorcode) { |
1476 return; |
1580 return; |
1477 } |
1581 } |
1478 |
1582 |
1479 // Consume from keyword |
1583 // Consume FROM keyword |
1480 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1584 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1481 && tokenvalue_is(tokens, "from")) { |
1585 && tokenvalue_is(tokens, "from")) { |
1482 tokens = tokens->next; |
1586 tokens = tokens->next; |
1483 } else { |
1587 } else { |
1484 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
1588 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
1485 _error_missing_from, stmt, tokens); |
1589 _error_missing_from, stmt, tokens); |
1486 return; |
1590 return; |
1487 } |
1591 } |
1488 |
1592 |
1489 // Consume path |
1593 // Consume path |
1490 if (token_is(tokens, DAVQL_TOKEN_STRING)) { |
1594 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); |
1491 stmt->path = token_sstr(tokens); |
1595 if (stmt->errorcode) { |
1492 tokens = tokens->next; |
|
1493 } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) |
|
1494 && tokenvalue_is(tokens, "/")) { |
|
1495 stmt->path = token_sstr(tokens); |
|
1496 tokens = tokens->next; |
|
1497 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && |
|
1498 !token_is(tokens, DAVQL_TOKEN_END)) { |
|
1499 sstr_t toksstr = token_sstr(tokens); |
|
1500 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; |
|
1501 tokens = tokens->next; |
|
1502 } |
|
1503 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && |
|
1504 tokenvalue_is(tokens, "%s")) { |
|
1505 stmt->path = token_sstr(tokens); |
|
1506 tokens = tokens->next; |
|
1507 } else { |
|
1508 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1509 _error_missing_path, stmt, tokens); |
|
1510 return; |
1596 return; |
1511 } |
1597 } |
1512 |
1598 |
1513 // Consume with clause (if any) |
1599 // Consume with clause (if any) |
1514 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1600 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1525 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1611 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1526 && tokenvalue_is(tokens, "where")) { |
1612 && tokenvalue_is(tokens, "where")) { |
1527 tokens = tokens->next; |
1613 tokens = tokens->next; |
1528 tokens = ucx_list_get(tokens, |
1614 tokens = ucx_list_get(tokens, |
1529 dav_parse_where_clause(stmt, tokens)); |
1615 dav_parse_where_clause(stmt, tokens)); |
|
1616 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1617 && tokenvalue_is(tokens, "anywhere")) { |
|
1618 // useless, but the user may want to explicitly express his intent |
|
1619 tokens = tokens->next; |
|
1620 stmt->where = NULL; |
1530 } |
1621 } |
1531 if (stmt->errorcode) { |
1622 if (stmt->errorcode) { |
1532 return; |
1623 return; |
1533 } |
1624 } |
1534 |
1625 |
1564 } |
1655 } |
1565 |
1656 |
1566 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { |
1657 static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { |
1567 stmt->type = DAVQL_SET; |
1658 stmt->type = DAVQL_SET; |
1568 |
1659 |
1569 // TODO: make it so |
1660 // Consume assignments |
|
1661 tokens = ucx_list_get(tokens, dav_parse_assignments(stmt, tokens)); |
|
1662 if (stmt->errorcode) { |
|
1663 return; |
|
1664 } |
|
1665 |
|
1666 // Consume AT keyword |
|
1667 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1668 && tokenvalue_is(tokens, "at")) { |
|
1669 tokens = tokens->next; |
|
1670 } else { |
|
1671 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1672 _error_missing_at, stmt, tokens); |
|
1673 return; |
|
1674 } |
|
1675 |
|
1676 // Consume path |
|
1677 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); |
|
1678 if (stmt->errorcode) { |
|
1679 return; |
|
1680 } |
|
1681 |
|
1682 // Consume with clause (if any) |
|
1683 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1684 && tokenvalue_is(tokens, "with")) { |
|
1685 tokens = tokens->next; |
|
1686 tokens = ucx_list_get(tokens, |
|
1687 dav_parse_with_clause(stmt, tokens)); |
|
1688 } |
|
1689 if (stmt->errorcode) { |
|
1690 return; |
|
1691 } |
|
1692 |
|
1693 // Consume mandatory where clause (or anywhere keyword) |
|
1694 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1695 && tokenvalue_is(tokens, "where")) { |
|
1696 tokens = tokens->next; |
|
1697 tokens = ucx_list_get(tokens, |
|
1698 dav_parse_where_clause(stmt, tokens)); |
|
1699 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1700 && tokenvalue_is(tokens, "anywhere")) { |
|
1701 // no-op, but we want the user to be explicit about this |
|
1702 tokens = tokens->next; |
|
1703 stmt->where = NULL; |
|
1704 } else { |
|
1705 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1706 _error_missing_where, stmt, tokens); |
|
1707 return; |
|
1708 } |
1570 } |
1709 } |
1571 |
1710 |
1572 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
1711 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
1573 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
1712 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
1574 |
1713 |