# HG changeset patch # User Mike Becker # Date 1428944686 -7200 # Node ID e073cf4afc6a2a0ba7ea3161872daec01d0a4695 # Parent 838b427267bbe96a44683288306903ca909eec58 added order by clause to grammar + moved with clause right after the from clause diff -r 838b427267bb -r e073cf4afc6a libidav/davqlparser.c --- a/libidav/davqlparser.c Sat Apr 04 22:20:39 2015 +0200 +++ b/libidav/davqlparser.c Mon Apr 13 19:04:46 2015 +0200 @@ -246,6 +246,7 @@ #define _invalid_msg "invalid statement" #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)" #define _expected_token "expected token '%s' before '%.*s'" +#define _expected_by "expected by after order (order [->]%.*s)" #define _missing_quote "missing closing quote symbol (%.*s)" #define _parser_state "parser reached invalid state" #define _unknown_attribute "unknown attribute '%.*s'" @@ -483,18 +484,19 @@ static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) { stmt->type = DAVQL_GET; - /* - * 10: field list - * 20: FROM clause - * 530: expecting WHERE or WITH clause - * 30: WHERE clause - * 540: expecting WITH clause - * 541: expecting comma for WITH clause - * 40: WITH clause - * 500: expect end - * - */ - int step = 10; +#define _step_fieldlist_ 10 // field list +#define _step_FROM_ 20 // FROM clause +#define _step_expect_WWO_ 530 // expecting WITH, WHERE or ORDER BY clause +#define _step_comma_WITH_ 531 // expecting comma for WITH clause +#define _step_WITH_ 30 // WITH clause +#define _step_expect_WO 540 // expecting WHERE or ORDER BY clause +#define _step_WHERE_ 40 // WHERE clause +#define _step_expect_O 550 // expecting ORDER BY clause +#define _step_expect_BY 551 // expecting the BY token for the ORDER BY clause +#define _step_ORDER_BY_ 50 // ORDER BY clause +#define _step_end_ 500 // expect end + + int step = _step_fieldlist_; // Variables for token sublists for expressions UcxList *exprstart = NULL; @@ -510,33 +512,57 @@ switch (step) { // too much input data - case 500: + case _step_end_: dav_parse_unexpected_token(stmt, token); goto ultrabreak; // optional clauses - case 530: - if (!sstrcasecmp(tokendata, S("where"))) { - step = 30; + case _step_expect_WWO_: + if (!sstrcasecmp(tokendata, S("with"))) { + step = _step_WITH_; + continue; } /* no break and no else*/ - case 540: - if (!sstrcasecmp(tokendata, S("with"))) { - step = 40; - } else { + case _step_expect_WO: + if (!sstrcasecmp(tokendata, S("where"))) { + step = _step_WHERE_; + continue; + } + /* no break and no else*/ + case _step_expect_O: + if (!sstrcasecmp(tokendata, S("order"))) { + step = _step_expect_BY; + continue; + } else { // last possible clause checked and not present dav_parse_unexpected_token(stmt, token); goto ultrabreak; } break; - case 541: + case _step_expect_BY: + if (!sstrcasecmp(tokendata, S("by"))) { + step = _step_ORDER_BY_; + } else { + stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; + stmt->errormessage = ucx_sprintf(_expected_by, + sfmtarg(tokendata)).ptr; + goto ultrabreak; + } + break; + case _step_comma_WITH_: + // a with clause may be continued with a comma + // or another clause may follow if (!sstrcmp(tokendata, S(","))) { - step = 40; + step = _step_WITH_; + } if (!sstrcasecmp(tokendata, S("where"))) { + step = _step_WHERE_; + } else if (!sstrcasecmp(tokendata, S("order"))) { + step = _step_expect_BY; } else { dav_parse_unexpected_token(stmt, token); goto ultrabreak; } break; // field list - case 10: { + case _step_fieldlist_: { _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); if (fromkeyword || !sstrcmp(tokendata, S(","))) { if (exprstart) { @@ -549,7 +575,7 @@ } if (fromkeyword) { - step = 20; + step = _step_FROM_; } } else { // collect tokens for field expression @@ -563,7 +589,7 @@ break; } // from clause - case 20: { + case _step_FROM_: { DavQLExpression *expr = dav_parse_expression(stmt, token, 1); stmt->path = expr->srctext; int exprtype = expr->type; @@ -573,31 +599,37 @@ stmt->errormessage = ucx_sprintf(_identifier_expected, sfmtarg(tokendata)).ptr; } - step = 530; + step = _step_expect_WWO_; break; } - // where clause - case 30: - step = 540; - break; // with clause - case 40: { + case _step_WITH_: { int withclause_result = dav_parse_with_clause(stmt, token); if (withclause_result < 0) { stmt->errorcode = DAVQL_ERROR_INVALID; stmt->errormessage = strdup(_parser_state); } else if (withclause_result > 0) { - step = 541; + step = _step_comma_WITH_; } break; } + // where clause + case _step_WHERE_: + // TODO: implement + step = _step_end_; + break; + // order by clause + case _step_ORDER_BY_: + // TODO: implement + step = _step_end_; + break; default: stmt->errorcode = DAVQL_ERROR_INVALID; stmt->errormessage = strdup(_parser_state); } } - if (!stmt->errorcode && step < 500) { + if (!stmt->errorcode && step < _step_end_) { stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END; stmt->errormessage = strdup(_unexpected_end_msg); } diff -r 838b427267bb -r e073cf4afc6a libidav/davqlparser.h --- a/libidav/davqlparser.h Sat Apr 04 22:20:39 2015 +0200 +++ b/libidav/davqlparser.h Mon Apr 13 19:04:46 2015 +0200 @@ -54,12 +54,12 @@ * Enumeration of possible expression operators. */ typedef enum { - DAVQL_NOOP, + DAVQL_NOOP, DAVQL_CALL, DAVQL_ARGLIST, // internal representations DAVQL_ADD, DAVQL_SUB, DAVQL_MUL, DAVQL_DIV, - DAVQL_AND, DAVQL_OR, DAVQL_XOR, DAVQL_NEG, - DAVQL_NOT, DAVQL_LAND, DAVQL_LOR, DAVQL_LXOR, + DAVQL_AND, DAVQL_OR, DAVQL_XOR, DAVQL_NEG, // airthmetic + DAVQL_NOT, DAVQL_LAND, DAVQL_LOR, DAVQL_LXOR, // logical DAVQL_EQ, DAVQL_NEQ, DAVQL_LT, DAVQL_GT, DAVQL_LE, DAVQL_GE, - DAVQL_LIKE, DAVQL_UNLIKE + DAVQL_LIKE, DAVQL_UNLIKE // comparisons } davqloperator_t; /** @@ -110,7 +110,8 @@ * | FunctionCall | Identifier | Literal * | "(", Expression, ")"; * - * FunctionCall = Identifier, "(", Expression, ")"; + * FunctionCall = Identifier, "(", ArgumentList, ")"; + * ArgumentList = Expression, {",", Expression}; * Identifier = IdentifierChar - ?Digit?, {IdentifierChar} * | "`", ?Character?, {?Character?}, "`"; * IdentifierChar = ?Character - (" "|",")?; @@ -134,11 +135,14 @@ * | "-"; * FieldExpression = Identifier * | Expression, " as ", String; - * SetExpressions = SetExpression, {",", {SetExpressions}; + * SetExpressions = SetExpression, {",", SetExpressions}; * SetExpression = Identifier, "=", Expression; * * WithClause = "depth", "=", (Number | "infinity"); * + * OrderByClause = OrderByCriterion, {",", OrderByCriterion}; + * OrderByCriterion = (Identifier | Number), [" asc"|" desc"]; + * * * * Note: mandatory spaces are part of the grammar. But you may also insert an @@ -149,16 +153,17 @@ *
  * GetStatement = "get ", FieldExpressions,
  * " from ", Identifier,
+ * [" with ", WithClause],
  * [" where ", LogicalExpression],
- * [" with ", WithClause];
+ * [" order by ", OrderByClause];
   * 
* * SET: *
  * "set ",SetExpressions,
  * " at ", Identifier,
- * (" where ", LogicalExpression) | " anywhere",
- * [" with ", WithClause];
+ * [" with ", WithClause],
+ * (" where ", LogicalExpression) | " anywhere";
  * 
* */