X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=blobdiff_plain;f=src%2Ffrontend%2Fgrammar.y;h=31b71a0eba7665b94de03bd47c50a0cd989ff24e;hp=74e28dd837f7e8eb7a819e1a0a4ed2ebda032ffb;hb=5ced2b9eb4d4def7d3ad5b1172004293e7a68e0e;hpb=b9bc76b71c4e4e1174ba1a8af3e13d53840b7e16 diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 74e28dd..31b71a0 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -33,13 +33,28 @@ #include "core/store.h" #include "core/store-private.h" +#include "core/time.h" #include "utils/error.h" #include "utils/llist.h" +#include + #include #include +/* + * private helper functions + */ + +static sdb_store_matcher_t * +name_iter_matcher(int m_type, sdb_store_expr_t *iter, const char *cmp, + sdb_store_expr_t *expr); + +/* + * public API + */ + int sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner); @@ -48,6 +63,8 @@ sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner); void sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); +void +sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...); /* quick access to the current parse tree */ #define pt sdb_fe_yyget_extra(scanner)->parsetree @@ -55,6 +72,15 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); /* quick access to the parser mode */ #define parser_mode sdb_fe_yyget_extra(scanner)->mode +/* quick access to the parser's error buffer */ +#define errbuf sdb_fe_yyget_extra(scanner)->errbuf + +#define MODE_TO_STRING(m) \ + (((m) == SDB_PARSE_DEFAULT) ? "statement" \ + : ((m) == SDB_PARSE_COND) ? "condition" \ + : ((m) == SDB_PARSE_ARITH) ? "arithmetic expression" \ + : "UNKNOWN") + %} %pure-parser @@ -68,32 +94,48 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %union { const char *sstr; /* static string */ char *str; + int integer; sdb_data_t data; + sdb_time_t datetime; sdb_llist_t *list; sdb_conn_node_t *node; sdb_store_matcher_t *m; + sdb_store_expr_t *expr; + + sdb_metric_store_t metric_store; } %start statements %token SCANNER_ERROR -%token AND OR IS NOT MATCHING +%token AND OR IS NOT MATCHING FILTER %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX -%token CMP_LT CMP_LE CMP_GE CMP_GT +%token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN +%token CONCAT + +%token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T +%token ATTRIBUTE_T ATTRIBUTES_T +%token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T VALUE_T + +%token LAST UPDATE + +%token START END /* NULL token */ %token NULL_T -%token FETCH LIST LOOKUP +%token FETCH LIST LOOKUP STORE TIMESERIES %token IDENTIFIER STRING %token INTEGER FLOAT +%token DATE TIME + /* Precedence (lowest first): */ %left OR %left AND @@ -101,7 +143,12 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %left CMP_EQUAL CMP_NEQUAL %left CMP_LT CMP_LE CMP_GE CMP_GT %nonassoc CMP_REGEX CMP_NREGEX +%nonassoc IN +%left CONCAT %nonassoc IS +%left '+' '-' +%left '*' '/' '%' +%left '[' ']' %left '(' ')' %left '.' @@ -110,28 +157,46 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); fetch_statement list_statement lookup_statement - expression + store_statement + timeseries_statement + matching_clause + filter_clause + condition %type matcher compare_matcher -%type op +%type expression arithmetic_expression object_expression + +%type object_type object_type_plural +%type field + +%type cmp %type data + interval interval_elem + array array_elem_list + +%type datetime + start_clause end_clause + last_update_clause + +%type metric_store_clause %destructor { free($$); } -%destructor { sdb_object_deref(SDB_OBJ($$)); } +%destructor { sdb_object_deref(SDB_OBJ($$)); } +%destructor { sdb_data_free_datum(&$$); } %% statements: statements ';' statement { - /* only accept this in default parse mode */ + /* only accepted in default parse mode */ if (parser_mode != SDB_PARSE_DEFAULT) { - sdb_fe_yyerror(&yylloc, scanner, + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, unexpected statement, " - "expecting expression")); + "expecting %s"), MODE_TO_STRING(parser_mode)); sdb_object_deref(SDB_OBJ($3)); YYABORT; } @@ -144,11 +209,11 @@ statements: | statement { - /* only accept this in default parse mode */ + /* only accepted in default parse mode */ if (parser_mode != SDB_PARSE_DEFAULT) { - sdb_fe_yyerror(&yylloc, scanner, + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, unexpected statement, " - "expecting expression")); + "expecting %s"), MODE_TO_STRING(parser_mode)); sdb_object_deref(SDB_OBJ($1)); YYABORT; } @@ -159,13 +224,13 @@ statements: } } | - expression + condition { - /* only accept this in expression parse mode */ - if (! (parser_mode & SDB_PARSE_EXPR)) { - sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, unexpected expression, " - "expecting statement")); + /* only accepted in condition parse mode */ + if (! (parser_mode & SDB_PARSE_COND)) { + sdb_fe_yyerrorf(&yylloc, scanner, + YY_("syntax error, unexpected condition, " + "expecting %s"), MODE_TO_STRING(parser_mode)); sdb_object_deref(SDB_OBJ($1)); YYABORT; } @@ -175,6 +240,29 @@ statements: sdb_object_deref(SDB_OBJ($1)); } } + | + expression + { + /* only accepted in expression parse mode */ + if (! (parser_mode & SDB_PARSE_ARITH)) { + sdb_fe_yyerrorf(&yylloc, scanner, + YY_("syntax error, unexpected expression, " + "expecting %s"), MODE_TO_STRING(parser_mode)); + sdb_object_deref(SDB_OBJ($1)); + YYABORT; + } + + if ($1) { + sdb_conn_node_t *n; + n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_expr_t, conn_expr_destroy)); + n->cmd = SDB_CONNECTION_EXPR; + CONN_EXPR(n)->expr = $1; + + sdb_llist_append(pt, SDB_OBJ(n)); + sdb_object_deref(SDB_OBJ(n)); + } + } ; statement: @@ -184,6 +272,10 @@ statement: | lookup_statement | + store_statement + | + timeseries_statement + | /* empty */ { $$ = NULL; @@ -191,75 +283,211 @@ statement: ; /* - * FETCH ; + * FETCH [FILTER ]; * * Retrieve detailed information about a single host. */ fetch_statement: - FETCH STRING + FETCH object_type STRING filter_clause { $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, conn_fetch_t, conn_fetch_destroy)); - CONN_FETCH($$)->name = strdup($2); - $$->cmd = CONNECTION_FETCH; - free($2); $2 = NULL; + CONN_FETCH($$)->type = $2; + CONN_FETCH($$)->host = $3; + CONN_FETCH($$)->name = NULL; + CONN_FETCH($$)->filter = CONN_MATCHER($4); + $$->cmd = SDB_CONNECTION_FETCH; + } + | + FETCH object_type STRING '.' STRING filter_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_fetch_t, conn_fetch_destroy)); + CONN_FETCH($$)->type = $2; + CONN_FETCH($$)->host = $3; + CONN_FETCH($$)->name = $5; + CONN_FETCH($$)->filter = CONN_MATCHER($6); + $$->cmd = SDB_CONNECTION_FETCH; } ; /* - * LIST; + * LIST [FILTER ]; * * Returns a list of all hosts in the store. */ list_statement: - LIST + LIST object_type_plural filter_clause { - $$ = SDB_CONN_NODE(sdb_object_create_T(/* name = */ NULL, - sdb_conn_node_t)); - $$->cmd = CONNECTION_LIST; + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_list_t, conn_list_destroy)); + CONN_LIST($$)->type = $2; + CONN_LIST($$)->filter = CONN_MATCHER($3); + $$->cmd = SDB_CONNECTION_LIST; } ; /* - * LOOKUP MATCHING ; + * LOOKUP MATCHING [FILTER ]; * - * Returns detailed information about matching expression. + * Returns detailed information about matching condition. */ lookup_statement: - LOOKUP IDENTIFIER MATCHING expression - { - /* TODO: support other types as well */ - if (strcasecmp($2, "hosts")) { - char errmsg[strlen($2) + 32]; - snprintf(errmsg, sizeof(errmsg), - YY_("unknown table %s"), $2); - sdb_fe_yyerror(&yylloc, scanner, errmsg); - free($2); $2 = NULL; - sdb_object_deref(SDB_OBJ($4)); - YYABORT; - } - + LOOKUP object_type_plural matching_clause filter_clause + { $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, conn_lookup_t, conn_lookup_destroy)); - CONN_LOOKUP($$)->matcher = CONN_MATCHER($4); - $$->cmd = CONNECTION_LOOKUP; - free($2); $2 = NULL; + CONN_LOOKUP($$)->type = $2; + CONN_LOOKUP($$)->matcher = CONN_MATCHER($3); + CONN_LOOKUP($$)->filter = CONN_MATCHER($4); + $$->cmd = SDB_CONNECTION_LOOKUP; } ; -expression: +matching_clause: + MATCHING condition { $$ = $2; } + | + /* empty */ { $$ = NULL; } + +filter_clause: + FILTER condition { $$ = $2; } + | + /* empty */ { $$ = NULL; } + +/* + * STORE |. [LAST UPDATE ]; + * STORE METRIC . STORE [LAST UPDATE ]; + * STORE ATTRIBUTE . [LAST UPDATE ]; + * + * Store or update an object in the database. + */ +store_statement: + STORE HOST_T STRING last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_host_t, conn_store_host_destroy)); + CONN_STORE_HOST($$)->name = $3; + CONN_STORE_HOST($$)->last_update = $4; + $$->cmd = SDB_CONNECTION_STORE_HOST; + } + | + STORE SERVICE_T STRING '.' STRING last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_svc_t, conn_store_svc_destroy)); + CONN_STORE_SVC($$)->hostname = $3; + CONN_STORE_SVC($$)->name = $5; + CONN_STORE_SVC($$)->last_update = $6; + $$->cmd = SDB_CONNECTION_STORE_SERVICE; + } + | + STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_metric_t, conn_store_metric_destroy)); + CONN_STORE_METRIC($$)->hostname = $3; + CONN_STORE_METRIC($$)->name = $5; + CONN_STORE_METRIC($$)->store_type = $6.type; + CONN_STORE_METRIC($$)->store_id = $6.id; + CONN_STORE_METRIC($$)->last_update = $7; + $$->cmd = SDB_CONNECTION_STORE_METRIC; + } + | + STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_attr_t, conn_store_attr_destroy)); + CONN_STORE_ATTR($$)->parent_type = SDB_HOST; + CONN_STORE_ATTR($$)->hostname = NULL; + CONN_STORE_ATTR($$)->parent = $4; + CONN_STORE_ATTR($$)->key = $6; + CONN_STORE_ATTR($$)->value = $7; + CONN_STORE_ATTR($$)->last_update = $8; + $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; + } + | + STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_attr_t, conn_store_attr_destroy)); + CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE; + CONN_STORE_ATTR($$)->hostname = $4; + CONN_STORE_ATTR($$)->parent = $6; + CONN_STORE_ATTR($$)->key = $8; + CONN_STORE_ATTR($$)->value = $9; + CONN_STORE_ATTR($$)->last_update = $10; + $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; + } + | + STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_store_attr_t, conn_store_attr_destroy)); + CONN_STORE_ATTR($$)->parent_type = SDB_METRIC; + CONN_STORE_ATTR($$)->hostname = $4; + CONN_STORE_ATTR($$)->parent = $6; + CONN_STORE_ATTR($$)->key = $8; + CONN_STORE_ATTR($$)->value = $9; + CONN_STORE_ATTR($$)->last_update = $10; + $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE; + } + ; + +last_update_clause: + LAST UPDATE datetime { $$ = $3; } + | + /* empty */ { $$ = sdb_gettime(); } + +metric_store_clause: + STORE STRING STRING { $$.type = $2; $$.id = $3; } + | + /* empty */ { $$.type = $$.id = NULL; } + +/* + * TIMESERIES . [START ] [END ]; + * + * Returns a time-series for the specified host's metric. + */ +timeseries_statement: + TIMESERIES STRING '.' STRING start_clause end_clause + { + $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, + conn_ts_t, conn_ts_destroy)); + CONN_TS($$)->hostname = $2; + CONN_TS($$)->metric = $4; + CONN_TS($$)->opts.start = $5; + CONN_TS($$)->opts.end = $6; + $$->cmd = SDB_CONNECTION_TIMESERIES; + } + ; + +start_clause: + START datetime { $$ = $2; } + | + /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; } + +end_clause: + END datetime { $$ = $2; } + | + /* empty */ { $$ = sdb_gettime(); } + +/* + * Basic expressions. + */ + +condition: matcher { if (! $1) { /* TODO: improve error reporting */ sdb_fe_yyerror(&yylloc, scanner, - YY_("syntax error, invalid expression")); + YY_("syntax error, invalid condition")); YYABORT; } $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL, - conn_node_matcher_t, conn_matcher_destroy)); - $$->cmd = CONNECTION_EXPR; + conn_matcher_t, conn_matcher_destroy)); + $$->cmd = SDB_CONNECTION_MATCHER; CONN_MATCHER($$)->matcher = $1; } ; @@ -296,48 +524,187 @@ matcher: } ; -/* - * . - * - * Parse matchers comparing object attributes with a value. - */ compare_matcher: - IDENTIFIER op data + expression cmp expression { - $$ = sdb_store_matcher_parse_cmp($1, NULL, $2, &$3); - free($1); $1 = NULL; - sdb_data_free_datum(&$3); + sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2); + assert(cb); /* else, the grammar accepts invalid 'cmp' */ + $$ = cb($1, $3); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($3)); } | - IDENTIFIER '.' IDENTIFIER op data + ANY expression cmp expression { - $$ = sdb_store_matcher_parse_cmp($1, $3, $4, &$5); - free($1); $1 = NULL; - free($3); $3 = NULL; - sdb_data_free_datum(&$5); + $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4); + sdb_object_deref(SDB_OBJ($2)); + sdb_object_deref(SDB_OBJ($4)); } | - IDENTIFIER '.' IDENTIFIER IS NULL_T + ALL expression cmp expression { - $$ = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL); - free($1); $1 = NULL; - free($3); $3 = NULL; + $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4); + sdb_object_deref(SDB_OBJ($2)); + sdb_object_deref(SDB_OBJ($4)); } | - IDENTIFIER '.' IDENTIFIER IS NOT NULL_T + expression IS NULL_T { - sdb_store_matcher_t *m; - m = sdb_store_matcher_parse_cmp($1, $3, "IS", NULL); - free($1); $1 = NULL; - free($3); $3 = NULL; + $$ = sdb_store_isnull_matcher($1); + sdb_object_deref(SDB_OBJ($1)); + } + | + expression IS NOT NULL_T + { + $$ = sdb_store_isnnull_matcher($1); + sdb_object_deref(SDB_OBJ($1)); + } + | + expression IN expression + { + $$ = sdb_store_in_matcher($1, $3); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($3)); + } + | + expression NOT IN expression + { + $$ = sdb_store_nin_matcher($1, $4); + sdb_object_deref(SDB_OBJ($1)); + sdb_object_deref(SDB_OBJ($4)); + } + ; + +expression: + arithmetic_expression + { + if (! $1) { + /* we should have better error messages here + * TODO: maybe let the analyzer handle this instead */ + sdb_fe_yyerror(&yylloc, scanner, + YY_("syntax error, invalid arithmetic expression")); + YYABORT; + } + $$ = $1; + } + | + object_expression + { + $$ = $1; + } + | + data + { + $$ = sdb_store_expr_constvalue(&$1); + sdb_data_free_datum(&$1); + } + ; + +arithmetic_expression: + '(' expression ')' + { + $$ = $2; + } + | + expression '+' expression + { + $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '-' expression + { + $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '*' expression + { + $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '/' expression + { + $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression '%' expression + { + $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + | + expression CONCAT expression + { + $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3); + sdb_object_deref(SDB_OBJ($1)); $1 = NULL; + sdb_object_deref(SDB_OBJ($3)); $3 = NULL; + } + ; - /* sdb_store_inv_matcher return NULL if m==NULL */ - $$ = sdb_store_inv_matcher(m); - sdb_object_deref(SDB_OBJ(m)); +object_expression: + object_type '.' object_expression + { + $$ = sdb_store_expr_typed($1, $3); + sdb_object_deref(SDB_OBJ($3)); + } + | + ATTRIBUTE_T '.' object_expression + { + $$ = sdb_store_expr_typed(SDB_ATTRIBUTE, $3); + sdb_object_deref(SDB_OBJ($3)); } + | + field + { + $$ = sdb_store_expr_fieldvalue($1); + } + | + ATTRIBUTE_T '[' STRING ']' + { + $$ = sdb_store_expr_attrvalue($3); + free($3); $3 = NULL; + } + ; + +object_type: + HOST_T { $$ = SDB_HOST; } + | + SERVICE_T { $$ = SDB_SERVICE; } + | + METRIC_T { $$ = SDB_METRIC; } + ; + +object_type_plural: + HOSTS_T { $$ = SDB_HOST; } + | + SERVICES_T { $$ = SDB_SERVICE; } + | + METRICS_T { $$ = SDB_METRIC; } ; -op: +field: + NAME_T { $$ = SDB_FIELD_NAME; } + | + LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; } + | + AGE_T { $$ = SDB_FIELD_AGE; } + | + INTERVAL_T { $$ = SDB_FIELD_INTERVAL; } + | + BACKEND_T { $$ = SDB_FIELD_BACKEND; } + | + VALUE_T { $$ = SDB_FIELD_VALUE; } + ; + +cmp: CMP_EQUAL { $$ = "="; } | CMP_NEQUAL { $$ = "!="; } @@ -361,6 +728,117 @@ data: INTEGER { $$ = $1; } | FLOAT { $$ = $1; } + | + datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; } + | + interval { $$ = $1; } + | + array { $$ = $1; } + ; + +datetime: + DATE TIME { $$ = $1 + $2; } + | + DATE { $$ = $1; } + | + TIME { $$ = $1; } + ; + +interval: + interval interval_elem + { + $$.data.datetime = $1.data.datetime + $2.data.datetime; + } + | + interval_elem { $$ = $1; } + ; + +interval_elem: + INTEGER IDENTIFIER + { + sdb_time_t unit = 1; + + unit = sdb_strpunit($2); + if (! unit) { + sdb_fe_yyerrorf(&yylloc, scanner, + YY_("syntax error, invalid time unit %s"), $2); + free($2); $2 = NULL; + YYABORT; + } + free($2); $2 = NULL; + + $$.type = SDB_TYPE_DATETIME; + $$.data.datetime = (sdb_time_t)$1.data.integer * unit; + + if ($1.data.integer < 0) { + sdb_fe_yyerror(&yylloc, scanner, + YY_("syntax error, negative intervals not supported")); + YYABORT; + } + } + ; + +array: + '[' array_elem_list ']' + { + $$ = $2; + } + ; + +array_elem_list: + array_elem_list ',' data + { + size_t elem_size; + + if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) { + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " + "cannot use element of type %s in array of type %s"), + SDB_TYPE_TO_STRING($3.type), + SDB_TYPE_TO_STRING($1.type)); + sdb_data_free_datum(&$1); + sdb_data_free_datum(&$3); + YYABORT; + } + + elem_size = sdb_data_sizeof($3.type); + $1.data.array.values = realloc($1.data.array.values, + ($1.data.array.length + 1) * elem_size); + if (! $1.data.array.values) { + sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); + YYABORT; + } + + memcpy((char *)$1.data.array.values + + $1.data.array.length * elem_size, + &$3.data, elem_size); + ++$1.data.array.length; + + $$ = $1; + } + | + data + { + size_t elem_size; + + if ($1.type & SDB_TYPE_ARRAY) { + sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, " + "cannot construct array of type %s"), + SDB_TYPE_TO_STRING($1.type)); + sdb_data_free_datum(&$1); + YYABORT; + } + + $$ = $1; + $$.type = $1.type | SDB_TYPE_ARRAY; + $$.data.array.length = 1; + elem_size = sdb_data_sizeof($1.type); + $$.data.array.values = malloc(elem_size); + if (! $$.data.array.values ) { + sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory")); + YYABORT; + } + memcpy($$.data.array.values, &$1.data, elem_size); + } ; %% @@ -369,7 +847,36 @@ void sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg) { sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg); + sdb_strbuf_sprintf(errbuf, "%s", msg); } /* sdb_fe_yyerror */ +void +sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...) +{ + va_list ap, aq; + va_start(ap, fmt); + va_copy(aq, ap); + sdb_vlog(SDB_LOG_ERR, fmt, ap); + sdb_strbuf_vsprintf(errbuf, fmt, aq); + va_end(ap); +} /* sdb_fe_yyerrorf */ + +static sdb_store_matcher_t * +name_iter_matcher(int type, sdb_store_expr_t *iter, const char *cmp, + sdb_store_expr_t *expr) +{ + sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp); + sdb_store_matcher_t *m, *tmp = NULL; + assert(cb); + + m = cb(NULL, expr); + if (type == MATCHER_ANY) + tmp = sdb_store_any_matcher(iter, m); + else if (type == MATCHER_ALL) + tmp = sdb_store_all_matcher(iter, m); + sdb_object_deref(SDB_OBJ(m)); + return tmp; +} /* name_iter_matcher */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */