Tue, 28 Apr 2015 16:43:57 +0200
fieldlist parser can now parse fields with alias
libidav/davqlparser.c | file | annotate | diff | comparison | revisions |
--- a/libidav/davqlparser.c Tue Apr 21 12:13:41 2015 +0200 +++ b/libidav/davqlparser.c Tue Apr 28 16:43:57 2015 +0200 @@ -508,7 +508,6 @@ sstr_t tokendata = *token_sstr(token); // TODO: make it so - printf("Processing %.*s...\n", sfmtarg(tokendata)); // go to next token (if this is not the last token) if (i < n-1) { @@ -544,62 +543,151 @@ struct fieldlist_parser_state { UcxList *expr_firsttoken; + DavQLField *currentfield; size_t expr_len; /* * 0: begin of field list - may encounter "*" or "-" special fields * 1: collect expression token * switch to step 2 on keyword "as" - * expect "," only if expr_len is 1 (add expr to list and continue) - * 2: expect one token (identifier) and a "," - continue with step 1 + * expect "," or "from" only if expr_len is 1 (add to list and continue) + * 2: expect one token (identifier) for as clause + * 3: expect a ",": continue with step 1 + * or a "from": leave field list parser + * 4: expect end of field list (i.e. a "from" keyword) */ int step; }; +static void dav_free_field(DavQLField *field) { + dav_free_expression(field->expr); + free(field); +} + static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token, struct fieldlist_parser_state *state) { sstr_t tokendata = *token_sstr(token); + + _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); + _Bool comma = !sstrcmp(tokendata, S(",")); switch (state->step) { case 0: + if (!sstrcmp(tokendata, S("*")) || !sstrcmp(tokendata, S("-"))) { + DavQLField *field = malloc(sizeof(DavQLField)); + field->name = tokendata; + field->expr = calloc(1, sizeof(DavQLExpression)); + field->expr->type = DAVQL_IDENTIFIER; + field->expr->srctext = tokendata; + stmt->fields = ucx_list_append(stmt->fields, field); + + if (tokendata.ptr[0] == '-') { + // no further fields may follow, if dash symbol has been found + state->step = 4; + } else { + state->step = 3; + } + return _step_fieldlist_; + } // did not encounter special field, fall through to step 1 + state->step = 1; case 1: - break; - } - - _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); - if (fromkeyword || !sstrcmp(tokendata, S(","))) { - if (state->expr_firsttoken) { - DavQLField *field = malloc(sizeof(DavQLField)); - field->expr = dav_parse_expression( + if (fromkeyword || comma) { + // add possible identifier to list + if (state->expr_firsttoken) { + // TODO: skip comma in function call) + if (state->expr_len > 1) { + stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; + stmt->errormessage = ucx_sprintf(_expected_token, + "AS", sfmtarg(tokendata)).ptr; + return 0; + } + + DavQLExpression *expr = dav_parse_expression( + stmt, state->expr_firsttoken, state->expr_len); + + if (expr->type != DAVQL_IDENTIFIER) { + dav_free_expression(expr); + stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; + stmt->errormessage = ucx_sprintf(_expected_token, + "AS", sfmtarg(tokendata)).ptr; + return 0; + } // TODO: do not allow identifier when wildcard is present + + DavQLField *field = malloc(sizeof(DavQLField)); + field->expr = expr; + field->name = field->expr->srctext; + stmt->fields = ucx_list_append(stmt->fields, field); + + state->expr_firsttoken = NULL; + state->expr_len = 0; + + if (fromkeyword) { + return _step_FROM_; + } + } else { + dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, + _unexpected_token, stmt, token); + return 0; + } + } else if (!sstrcasecmp(tokendata, S("as"))) { + // TODO: return error, if expr_first_token is NULL + state->currentfield = malloc(sizeof(DavQLField)); + state->currentfield->expr = dav_parse_expression( stmt, state->expr_firsttoken, state->expr_len); - field->name = field->expr->srctext; - stmt->fields = ucx_list_append(stmt->fields, field); + state->expr_firsttoken = NULL; state->expr_len = 0; - - if (fromkeyword) { - return _step_FROM_; + + state->step = 2; + } else { + // collect tokens for field expression + if (state->expr_firsttoken) { + state->expr_len++; + } else { + state->expr_firsttoken = token; + state->expr_len = 1; } + } + + return _step_fieldlist_; + case 2: { + DavQLExpression *expr = dav_parse_expression(stmt, token, 1); + if (expr->type == DAVQL_IDENTIFIER) { + state->currentfield->name = expr->srctext; + stmt->fields = ucx_list_append(stmt->fields, state->currentfield); + state->currentfield = NULL; + } else { + dav_free_field(state->currentfield); + dav_error_in_context(DAVQL_ERROR_IDENTIFIER_EXPECTED, + _identifier_expected, stmt, token); + + } + dav_free_expression(expr); + state->step = 3; + + return _step_fieldlist_; + } + case 3: + if (fromkeyword) { + return _step_FROM_; + } else if (comma) { + state->step = 1; + return _step_fieldlist_; } else { dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, _unexpected_token, stmt, token); + return 0; } - } else { - // collect tokens for field expression - if (state->expr_firsttoken) { - state->expr_len++; + case 4: + if (fromkeyword) { + return _step_FROM_; } else { - state->expr_firsttoken = token; - state->expr_len = 1; + stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN; + stmt->errormessage = ucx_sprintf(_expected_token, + "FROM", sfmtarg(tokendata)).ptr; + return 0; } } - - return _step_fieldlist_; -} - -static void dav_free_field(DavQLField *field) { - dav_free_expression(field->expr); - free(field); } static int dav_parse_from(DavQLStatement *stmt, UcxList *token) {