392 #define _error_out_of_memory "out of memory" |
392 #define _error_out_of_memory "out of memory" |
393 #define _error_unexpected_token "unexpected token " _error_context |
393 #define _error_unexpected_token "unexpected token " _error_context |
394 #define _error_invalid_token "invalid token " _error_context |
394 #define _error_invalid_token "invalid token " _error_context |
395 #define _error_missing_path "expected path " _error_context |
395 #define _error_missing_path "expected path " _error_context |
396 #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 |
397 #define _error_missing_by "expecting BY keyword " _error_context |
398 #define _error_missing_by "expecting BY keyword " _error_context |
398 #define _error_missing_as "expecting alias ('as <identifier>') " _error_context |
399 #define _error_missing_as "expecting alias ('as <identifier>') " _error_context |
399 #define _error_missing_identifier "expecting identifier " _error_context |
400 #define _error_missing_identifier "expecting identifier " _error_context |
400 #define _error_missing_par "missing closed parenthesis " _error_context |
401 #define _error_missing_par "missing closed parenthesis " _error_context |
401 #define _error_missing_assign "expecting assignment ('=') " _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 |
402 #define _error_invalid_depth "invalid depth " _error_context |
405 #define _error_invalid_depth "invalid depth " _error_context |
403 #define _error_missing_expr "missing expression " _error_context |
406 #define _error_missing_expr "missing expression " _error_context |
404 #define _error_invalid_expr "invalid expression " _error_context |
407 #define _error_invalid_expr "invalid expression " _error_context |
405 #define _error_invalid_unary_op "invalid unary operator " _error_context |
408 #define _error_invalid_unary_op "invalid unary operator " _error_context |
406 #define _error_invalid_logical_op "invalid logical operator " _error_context |
409 #define _error_invalid_logical_op "invalid logical operator " _error_context |
1531 } while (consumed); |
1534 } while (consumed); |
1532 |
1535 |
1533 return total_consumed; |
1536 return total_consumed; |
1534 } |
1537 } |
1535 |
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 |
1536 /** |
1569 /** |
1537 * Parser of a select statement. |
1570 * Parser of a select statement. |
1538 * @param stmt the statement object that shall contain the syntax tree |
1571 * @param stmt the statement object that shall contain the syntax tree |
1539 * @param tokens the token list |
1572 * @param tokens the token list |
1540 */ |
1573 */ |
1545 tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); |
1578 tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); |
1546 if (stmt->errorcode) { |
1579 if (stmt->errorcode) { |
1547 return; |
1580 return; |
1548 } |
1581 } |
1549 |
1582 |
1550 // Consume from keyword |
1583 // Consume FROM keyword |
1551 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1584 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1552 && tokenvalue_is(tokens, "from")) { |
1585 && tokenvalue_is(tokens, "from")) { |
1553 tokens = tokens->next; |
1586 tokens = tokens->next; |
1554 } else { |
1587 } else { |
1555 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
1588 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
1556 _error_missing_from, stmt, tokens); |
1589 _error_missing_from, stmt, tokens); |
1557 return; |
1590 return; |
1558 } |
1591 } |
1559 |
1592 |
1560 // Consume path |
1593 // Consume path |
1561 if (token_is(tokens, DAVQL_TOKEN_STRING)) { |
1594 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); |
1562 stmt->path = token_sstr(tokens); |
1595 if (stmt->errorcode) { |
1563 tokens = tokens->next; |
|
1564 } else if (token_is(tokens, DAVQL_TOKEN_OPERATOR) |
|
1565 && tokenvalue_is(tokens, "/")) { |
|
1566 stmt->path = token_sstr(tokens); |
|
1567 tokens = tokens->next; |
|
1568 while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && |
|
1569 !token_is(tokens, DAVQL_TOKEN_END)) { |
|
1570 sstr_t toksstr = token_sstr(tokens); |
|
1571 stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; |
|
1572 tokens = tokens->next; |
|
1573 } |
|
1574 } else if (token_is(tokens, DAVQL_TOKEN_FMTSPEC) && |
|
1575 tokenvalue_is(tokens, "%s")) { |
|
1576 stmt->path = token_sstr(tokens); |
|
1577 tokens = tokens->next; |
|
1578 } else { |
|
1579 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1580 _error_missing_path, stmt, tokens); |
|
1581 return; |
1596 return; |
1582 } |
1597 } |
1583 |
1598 |
1584 // Consume with clause (if any) |
1599 // Consume with clause (if any) |
1585 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1600 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
1641 tokens = ucx_list_get(tokens, dav_parse_assignments(stmt, tokens)); |
1656 tokens = ucx_list_get(tokens, dav_parse_assignments(stmt, tokens)); |
1642 if (stmt->errorcode) { |
1657 if (stmt->errorcode) { |
1643 return; |
1658 return; |
1644 } |
1659 } |
1645 |
1660 |
1646 // TODO: make it so |
1661 // Consume AT keyword |
|
1662 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1663 && tokenvalue_is(tokens, "at")) { |
|
1664 tokens = tokens->next; |
|
1665 } else { |
|
1666 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1667 _error_missing_at, stmt, tokens); |
|
1668 return; |
|
1669 } |
|
1670 |
|
1671 // Consume path |
|
1672 tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); |
|
1673 if (stmt->errorcode) { |
|
1674 return; |
|
1675 } |
|
1676 |
|
1677 // Consume with clause (if any) |
|
1678 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1679 && tokenvalue_is(tokens, "with")) { |
|
1680 tokens = tokens->next; |
|
1681 tokens = ucx_list_get(tokens, |
|
1682 dav_parse_with_clause(stmt, tokens)); |
|
1683 } |
|
1684 if (stmt->errorcode) { |
|
1685 return; |
|
1686 } |
|
1687 |
|
1688 // Consume mandatory where clause (or anywhere keyword) |
|
1689 if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1690 && tokenvalue_is(tokens, "where")) { |
|
1691 tokens = tokens->next; |
|
1692 tokens = ucx_list_get(tokens, |
|
1693 dav_parse_where_clause(stmt, tokens)); |
|
1694 } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) |
|
1695 && tokenvalue_is(tokens, "anywhere")) { |
|
1696 // no-op, but we want the user to be explicit about this |
|
1697 stmt->where = NULL; |
|
1698 } else { |
|
1699 dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, |
|
1700 _error_missing_where, stmt, tokens); |
|
1701 } |
1647 } |
1702 } |
1648 |
1703 |
1649 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
1704 DavQLStatement* dav_parse_statement(sstr_t srctext) { |
1650 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
1705 DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); |
1651 |
1706 |