Code

Let iterator operators fill in the left operand of child operators.
[sysdb.git] / src / frontend / grammar.y
1 /*
2  * SysDB - src/frontend/grammar.y
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 %{
30 #include "frontend/connection-private.h"
31 #include "frontend/parser.h"
32 #include "frontend/grammar.h"
34 #include "core/store.h"
35 #include "core/store-private.h"
36 #include "core/time.h"
38 #include "utils/error.h"
39 #include "utils/llist.h"
41 #include <assert.h>
43 #include <stdio.h>
44 #include <string.h>
46 /*
47  * private helper functions
48  */
50 static sdb_store_matcher_t *
51 name_iter_matcher(int m_type, sdb_store_expr_t *iter, const char *cmp,
52                 sdb_store_expr_t *expr);
54 /*
55  * public API
56  */
58 int
59 sdb_fe_yylex(YYSTYPE *yylval, YYLTYPE *yylloc, sdb_fe_yyscan_t yyscanner);
61 sdb_fe_yyextra_t *
62 sdb_fe_yyget_extra(sdb_fe_yyscan_t scanner);
64 void
65 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg);
66 void
67 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...);
69 /* quick access to the current parse tree */
70 #define pt sdb_fe_yyget_extra(scanner)->parsetree
72 /* quick access to the parser mode */
73 #define parser_mode sdb_fe_yyget_extra(scanner)->mode
75 /* quick access to the parser's error buffer */
76 #define errbuf sdb_fe_yyget_extra(scanner)->errbuf
78 #define MODE_TO_STRING(m) \
79         (((m) == SDB_PARSE_DEFAULT) ? "statement" \
80                 : ((m) == SDB_PARSE_COND) ? "condition" \
81                 : ((m) == SDB_PARSE_EXPR) ? "expression" \
82                 : "UNKNOWN")
84 %}
86 %pure-parser
87 %lex-param {sdb_fe_yyscan_t scanner}
88 %parse-param {sdb_fe_yyscan_t scanner}
89 %locations
90 %error-verbose
91 %expect 0
92 %name-prefix "sdb_fe_yy"
94 %union {
95         const char *sstr; /* static string */
96         char *str;
97         int integer;
99         sdb_data_t data;
100         sdb_time_t datetime;
102         sdb_llist_t     *list;
103         sdb_conn_node_t *node;
105         sdb_store_matcher_t *m;
106         sdb_store_expr_t *expr;
108         sdb_metric_store_t metric_store;
111 %start statements
113 %token SCANNER_ERROR
115 %token AND OR IS NOT MATCHING FILTER
116 %token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX
117 %token CMP_LT CMP_LE CMP_GE CMP_GT ALL ANY IN
118 %token CONCAT
120 %token HOST_T HOSTS_T SERVICE_T SERVICES_T METRIC_T METRICS_T
121 %token ATTRIBUTE_T ATTRIBUTES_T
122 %token NAME_T LAST_UPDATE_T AGE_T INTERVAL_T BACKEND_T
124 %token LAST UPDATE
126 %token START END
128 /* NULL token */
129 %token NULL_T
131 %token FETCH LIST LOOKUP STORE TIMESERIES
133 %token <str> IDENTIFIER STRING
135 %token <data> INTEGER FLOAT
137 %token <datetime> DATE TIME
139 /* Precedence (lowest first): */
140 %left OR
141 %left AND
142 %right NOT
143 %left CMP_EQUAL CMP_NEQUAL
144 %left CMP_LT CMP_LE CMP_GE CMP_GT
145 %nonassoc CMP_REGEX CMP_NREGEX
146 %nonassoc IN
147 %left CONCAT
148 %nonassoc IS
149 %left '+' '-'
150 %left '*' '/' '%'
151 %left '[' ']'
152 %left '(' ')'
153 %left '.'
155 %type <list> statements
156 %type <node> statement
157         fetch_statement
158         list_statement
159         lookup_statement
160         store_statement
161         timeseries_statement
162         matching_clause
163         filter_clause
164         condition
166 %type <m> matcher
167         compare_matcher
169 %type <expr> expression arithmetic_expression object_expression
171 %type <integer> object_type object_type_plural
172 %type <integer> field
174 %type <sstr> cmp
176 %type <data> data
177         interval interval_elem
178         array array_elem_list
180 %type <datetime> datetime
181         start_clause end_clause
182         last_update_clause
184 %type <metric_store> metric_store_clause
186 %destructor { free($$); } <str>
187 %destructor { sdb_object_deref(SDB_OBJ($$)); } <node> <m> <expr>
188 %destructor { sdb_data_free_datum(&$$); } <data>
190 %%
192 statements:
193         statements ';' statement
194                 {
195                         /* only accepted in default parse mode */
196                         if (parser_mode != SDB_PARSE_DEFAULT) {
197                                 sdb_fe_yyerrorf(&yylloc, scanner,
198                                                 YY_("syntax error, unexpected statement, "
199                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
200                                 sdb_object_deref(SDB_OBJ($3));
201                                 YYABORT;
202                         }
204                         if ($3) {
205                                 sdb_llist_append(pt, SDB_OBJ($3));
206                                 sdb_object_deref(SDB_OBJ($3));
207                         }
208                 }
209         |
210         statement
211                 {
212                         /* only accepted in default parse mode */
213                         if (parser_mode != SDB_PARSE_DEFAULT) {
214                                 sdb_fe_yyerrorf(&yylloc, scanner,
215                                                 YY_("syntax error, unexpected statement, "
216                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
217                                 sdb_object_deref(SDB_OBJ($1));
218                                 YYABORT;
219                         }
221                         if ($1) {
222                                 sdb_llist_append(pt, SDB_OBJ($1));
223                                 sdb_object_deref(SDB_OBJ($1));
224                         }
225                 }
226         |
227         condition
228                 {
229                         /* only accepted in condition parse mode */
230                         if (! (parser_mode & SDB_PARSE_COND)) {
231                                 sdb_fe_yyerrorf(&yylloc, scanner,
232                                                 YY_("syntax error, unexpected condition, "
233                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
234                                 sdb_object_deref(SDB_OBJ($1));
235                                 YYABORT;
236                         }
238                         if ($1) {
239                                 sdb_llist_append(pt, SDB_OBJ($1));
240                                 sdb_object_deref(SDB_OBJ($1));
241                         }
242                 }
243         |
244         expression
245                 {
246                         /* only accepted in expression parse mode */
247                         if (! (parser_mode & SDB_PARSE_EXPR)) {
248                                 sdb_fe_yyerrorf(&yylloc, scanner,
249                                                 YY_("syntax error, unexpected expression, "
250                                                         "expecting %s"), MODE_TO_STRING(parser_mode));
251                                 sdb_object_deref(SDB_OBJ($1));
252                                 YYABORT;
253                         }
255                         if ($1) {
256                                 sdb_conn_node_t *n;
257                                 n = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
258                                                         conn_expr_t, conn_expr_destroy));
259                                 n->cmd = SDB_CONNECTION_EXPR;
260                                 CONN_EXPR(n)->expr = $1;
262                                 sdb_llist_append(pt, SDB_OBJ(n));
263                                 sdb_object_deref(SDB_OBJ(n));
264                         }
265                 }
266         ;
268 statement:
269         fetch_statement
270         |
271         list_statement
272         |
273         lookup_statement
274         |
275         store_statement
276         |
277         timeseries_statement
278         |
279         /* empty */
280                 {
281                         $$ = NULL;
282                 }
283         ;
285 /*
286  * FETCH <type> <hostname> [FILTER <condition>];
287  *
288  * Retrieve detailed information about a single host.
289  */
290 fetch_statement:
291         FETCH object_type STRING filter_clause
292                 {
293                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
294                                                 conn_fetch_t, conn_fetch_destroy));
295                         CONN_FETCH($$)->type = $2;
296                         CONN_FETCH($$)->host = $3;
297                         CONN_FETCH($$)->name = NULL;
298                         CONN_FETCH($$)->filter = CONN_MATCHER($4);
299                         $$->cmd = SDB_CONNECTION_FETCH;
300                 }
301         |
302         FETCH object_type STRING '.' STRING filter_clause
303                 {
304                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
305                                                 conn_fetch_t, conn_fetch_destroy));
306                         CONN_FETCH($$)->type = $2;
307                         CONN_FETCH($$)->host = $3;
308                         CONN_FETCH($$)->name = $5;
309                         CONN_FETCH($$)->filter = CONN_MATCHER($6);
310                         $$->cmd = SDB_CONNECTION_FETCH;
311                 }
312         ;
314 /*
315  * LIST <type> [FILTER <condition>];
316  *
317  * Returns a list of all hosts in the store.
318  */
319 list_statement:
320         LIST object_type_plural filter_clause
321                 {
322                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
323                                                 conn_list_t, conn_list_destroy));
324                         CONN_LIST($$)->type = $2;
325                         CONN_LIST($$)->filter = CONN_MATCHER($3);
326                         $$->cmd = SDB_CONNECTION_LIST;
327                 }
328         ;
330 /*
331  * LOOKUP <type> MATCHING <condition> [FILTER <condition>];
332  *
333  * Returns detailed information about <type> matching condition.
334  */
335 lookup_statement:
336         LOOKUP object_type_plural matching_clause filter_clause
337                 {
338                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
339                                                 conn_lookup_t, conn_lookup_destroy));
340                         CONN_LOOKUP($$)->type = $2;
341                         CONN_LOOKUP($$)->matcher = CONN_MATCHER($3);
342                         CONN_LOOKUP($$)->filter = CONN_MATCHER($4);
343                         $$->cmd = SDB_CONNECTION_LOOKUP;
344                 }
345         ;
347 matching_clause:
348         MATCHING condition { $$ = $2; }
349         |
350         /* empty */ { $$ = NULL; }
352 filter_clause:
353         FILTER condition { $$ = $2; }
354         |
355         /* empty */ { $$ = NULL; }
357 /*
358  * STORE <type> <name>|<host>.<name> [LAST UPDATE <datetime>];
359  * STORE METRIC <host>.<name> STORE <type> <id> [LAST UPDATE <datetime>];
360  * STORE <type> ATTRIBUTE <parent>.<key> <datum> [LAST UPDATE <datetime>];
361  *
362  * Store or update an object in the database.
363  */
364 store_statement:
365         STORE HOST_T STRING last_update_clause
366                 {
367                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
368                                                 conn_store_host_t, conn_store_host_destroy));
369                         CONN_STORE_HOST($$)->name = $3;
370                         CONN_STORE_HOST($$)->last_update = $4;
371                         $$->cmd = SDB_CONNECTION_STORE_HOST;
372                 }
373         |
374         STORE SERVICE_T STRING '.' STRING last_update_clause
375                 {
376                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
377                                                 conn_store_svc_t, conn_store_svc_destroy));
378                         CONN_STORE_SVC($$)->hostname = $3;
379                         CONN_STORE_SVC($$)->name = $5;
380                         CONN_STORE_SVC($$)->last_update = $6;
381                         $$->cmd = SDB_CONNECTION_STORE_SERVICE;
382                 }
383         |
384         STORE METRIC_T STRING '.' STRING metric_store_clause last_update_clause
385                 {
386                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
387                                                 conn_store_metric_t, conn_store_metric_destroy));
388                         CONN_STORE_METRIC($$)->hostname = $3;
389                         CONN_STORE_METRIC($$)->name = $5;
390                         CONN_STORE_METRIC($$)->store_type = $6.type;
391                         CONN_STORE_METRIC($$)->store_id = $6.id;
392                         CONN_STORE_METRIC($$)->last_update = $7;
393                         $$->cmd = SDB_CONNECTION_STORE_METRIC;
394                 }
395         |
396         STORE HOST_T ATTRIBUTE_T STRING '.' STRING data last_update_clause
397                 {
398                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
399                                                 conn_store_attr_t, conn_store_attr_destroy));
400                         CONN_STORE_ATTR($$)->parent_type = SDB_HOST;
401                         CONN_STORE_ATTR($$)->hostname = NULL;
402                         CONN_STORE_ATTR($$)->parent = $4;
403                         CONN_STORE_ATTR($$)->key = $6;
404                         CONN_STORE_ATTR($$)->value = $7;
405                         CONN_STORE_ATTR($$)->last_update = $8;
406                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
407                 }
408         |
409         STORE SERVICE_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
410                 {
411                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
412                                                 conn_store_attr_t, conn_store_attr_destroy));
413                         CONN_STORE_ATTR($$)->parent_type = SDB_SERVICE;
414                         CONN_STORE_ATTR($$)->hostname = $4;
415                         CONN_STORE_ATTR($$)->parent = $6;
416                         CONN_STORE_ATTR($$)->key = $8;
417                         CONN_STORE_ATTR($$)->value = $9;
418                         CONN_STORE_ATTR($$)->last_update = $10;
419                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
420                 }
421         |
422         STORE METRIC_T ATTRIBUTE_T STRING '.' STRING '.' STRING data last_update_clause
423                 {
424                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
425                                                 conn_store_attr_t, conn_store_attr_destroy));
426                         CONN_STORE_ATTR($$)->parent_type = SDB_METRIC;
427                         CONN_STORE_ATTR($$)->hostname = $4;
428                         CONN_STORE_ATTR($$)->parent = $6;
429                         CONN_STORE_ATTR($$)->key = $8;
430                         CONN_STORE_ATTR($$)->value = $9;
431                         CONN_STORE_ATTR($$)->last_update = $10;
432                         $$->cmd = SDB_CONNECTION_STORE_ATTRIBUTE;
433                 }
434         ;
436 last_update_clause:
437         LAST UPDATE datetime { $$ = $3; }
438         |
439         /* empty */ { $$ = sdb_gettime(); }
441 metric_store_clause:
442         STORE STRING STRING { $$.type = $2; $$.id = $3; }
443         |
444         /* empty */ { $$.type = $$.id = NULL; }
446 /*
447  * TIMESERIES <host>.<metric> [START <datetime>] [END <datetime>];
448  *
449  * Returns a time-series for the specified host's metric.
450  */
451 timeseries_statement:
452         TIMESERIES STRING '.' STRING start_clause end_clause
453                 {
454                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
455                                                 conn_ts_t, conn_ts_destroy));
456                         CONN_TS($$)->hostname = $2;
457                         CONN_TS($$)->metric = $4;
458                         CONN_TS($$)->opts.start = $5;
459                         CONN_TS($$)->opts.end = $6;
460                         $$->cmd = SDB_CONNECTION_TIMESERIES;
461                 }
462         ;
464 start_clause:
465         START datetime { $$ = $2; }
466         |
467         /* empty */ { $$ = sdb_gettime() - SDB_INTERVAL_HOUR; }
469 end_clause:
470         END datetime { $$ = $2; }
471         |
472         /* empty */ { $$ = sdb_gettime(); }
474 /*
475  * Basic expressions.
476  */
478 condition:
479         matcher
480                 {
481                         if (! $1) {
482                                 /* TODO: improve error reporting */
483                                 sdb_fe_yyerror(&yylloc, scanner,
484                                                 YY_("syntax error, invalid condition"));
485                                 YYABORT;
486                         }
488                         $$ = SDB_CONN_NODE(sdb_object_create_dT(/* name = */ NULL,
489                                                 conn_matcher_t, conn_matcher_destroy));
490                         $$->cmd = SDB_CONNECTION_MATCHER;
491                         CONN_MATCHER($$)->matcher = $1;
492                 }
493         ;
495 matcher:
496         '(' matcher ')'
497                 {
498                         $$ = $2;
499                 }
500         |
501         matcher AND matcher
502                 {
503                         $$ = sdb_store_con_matcher($1, $3);
504                         sdb_object_deref(SDB_OBJ($1));
505                         sdb_object_deref(SDB_OBJ($3));
506                 }
507         |
508         matcher OR matcher
509                 {
510                         $$ = sdb_store_dis_matcher($1, $3);
511                         sdb_object_deref(SDB_OBJ($1));
512                         sdb_object_deref(SDB_OBJ($3));
513                 }
514         |
515         NOT matcher
516                 {
517                         $$ = sdb_store_inv_matcher($2);
518                         sdb_object_deref(SDB_OBJ($2));
519                 }
520         |
521         compare_matcher
522                 {
523                         $$ = $1;
524                 }
525         ;
527 compare_matcher:
528         expression cmp expression
529                 {
530                         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op($2);
531                         assert(cb); /* else, the grammar accepts invalid 'cmp' */
532                         $$ = cb($1, $3);
533                         sdb_object_deref(SDB_OBJ($1));
534                         sdb_object_deref(SDB_OBJ($3));
535                 }
536         |
537         ANY expression cmp expression
538                 {
539                         $$ = name_iter_matcher(MATCHER_ANY, $2, $3, $4);
540                         sdb_object_deref(SDB_OBJ($2));
541                         sdb_object_deref(SDB_OBJ($4));
542                 }
543         |
544         ALL expression cmp expression
545                 {
546                         $$ = name_iter_matcher(MATCHER_ALL, $2, $3, $4);
547                         sdb_object_deref(SDB_OBJ($2));
548                         sdb_object_deref(SDB_OBJ($4));
549                 }
550         |
551         expression IS NULL_T
552                 {
553                         $$ = sdb_store_isnull_matcher($1);
554                         sdb_object_deref(SDB_OBJ($1));
555                 }
556         |
557         expression IS NOT NULL_T
558                 {
559                         $$ = sdb_store_isnnull_matcher($1);
560                         sdb_object_deref(SDB_OBJ($1));
561                 }
562         |
563         expression IN expression
564                 {
565                         $$ = sdb_store_in_matcher($1, $3);
566                         sdb_object_deref(SDB_OBJ($1));
567                         sdb_object_deref(SDB_OBJ($3));
568                 }
569         |
570         expression NOT IN expression
571                 {
572                         $$ = sdb_store_nin_matcher($1, $4);
573                         sdb_object_deref(SDB_OBJ($1));
574                         sdb_object_deref(SDB_OBJ($4));
575                 }
576         ;
578 expression:
579         arithmetic_expression
580                 {
581                         if (! $1) {
582                                 /* we should have better error messages here
583                                  * TODO: maybe let the analyzer handle this instead */
584                                 sdb_fe_yyerror(&yylloc, scanner,
585                                                 YY_("syntax error, invalid arithmetic expression"));
586                                 YYABORT;
587                         }
588                         $$ = $1;
589                 }
590         |
591         object_expression
592                 {
593                         $$ = $1;
594                 }
595         |
596         data
597                 {
598                         $$ = sdb_store_expr_constvalue(&$1);
599                         sdb_data_free_datum(&$1);
600                 }
601         ;
603 arithmetic_expression:
604         '(' expression ')'
605                 {
606                         $$ = $2;
607                 }
608         |
609         expression '+' expression
610                 {
611                         $$ = sdb_store_expr_create(SDB_DATA_ADD, $1, $3);
612                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
613                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
614                 }
615         |
616         expression '-' expression
617                 {
618                         $$ = sdb_store_expr_create(SDB_DATA_SUB, $1, $3);
619                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
620                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
621                 }
622         |
623         expression '*' expression
624                 {
625                         $$ = sdb_store_expr_create(SDB_DATA_MUL, $1, $3);
626                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
627                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
628                 }
629         |
630         expression '/' expression
631                 {
632                         $$ = sdb_store_expr_create(SDB_DATA_DIV, $1, $3);
633                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
634                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
635                 }
636         |
637         expression '%' expression
638                 {
639                         $$ = sdb_store_expr_create(SDB_DATA_MOD, $1, $3);
640                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
641                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
642                 }
643         |
644         expression CONCAT expression
645                 {
646                         $$ = sdb_store_expr_create(SDB_DATA_CONCAT, $1, $3);
647                         sdb_object_deref(SDB_OBJ($1)); $1 = NULL;
648                         sdb_object_deref(SDB_OBJ($3)); $3 = NULL;
649                 }
650         ;
652 object_expression:
653         object_type '.' object_expression
654                 {
655                         $$ = sdb_store_expr_typed($1, $3);
656                         sdb_object_deref(SDB_OBJ($3));
657                 }
658         |
659         ATTRIBUTE_T '.' object_expression
660                 {
661                         $$ = sdb_store_expr_typed(SDB_ATTRIBUTE, $3);
662                         sdb_object_deref(SDB_OBJ($3));
663                 }
664         |
665         field
666                 {
667                         $$ = sdb_store_expr_fieldvalue($1);
668                 }
669         |
670         ATTRIBUTE_T '[' STRING ']'
671                 {
672                         $$ = sdb_store_expr_attrvalue($3);
673                         free($3); $3 = NULL;
674                 }
675         ;
677 object_type:
678         HOST_T { $$ = SDB_HOST; }
679         |
680         SERVICE_T { $$ = SDB_SERVICE; }
681         |
682         METRIC_T { $$ = SDB_METRIC; }
683         ;
685 object_type_plural:
686         HOSTS_T { $$ = SDB_HOST; }
687         |
688         SERVICES_T { $$ = SDB_SERVICE; }
689         |
690         METRICS_T { $$ = SDB_METRIC; }
691         ;
693 field:
694         NAME_T { $$ = SDB_FIELD_NAME; }
695         |
696         LAST_UPDATE_T { $$ = SDB_FIELD_LAST_UPDATE; }
697         |
698         AGE_T { $$ = SDB_FIELD_AGE; }
699         |
700         INTERVAL_T { $$ = SDB_FIELD_INTERVAL; }
701         |
702         BACKEND_T { $$ = SDB_FIELD_BACKEND; }
703         ;
705 cmp:
706         CMP_EQUAL { $$ = "="; }
707         |
708         CMP_NEQUAL { $$ = "!="; }
709         |
710         CMP_REGEX { $$ = "=~"; }
711         |
712         CMP_NREGEX { $$ = "!~"; }
713         |
714         CMP_LT { $$ = "<"; }
715         |
716         CMP_LE { $$ = "<="; }
717         |
718         CMP_GE { $$ = ">="; }
719         |
720         CMP_GT { $$ = ">"; }
721         ;
723 data:
724         STRING { $$.type = SDB_TYPE_STRING; $$.data.string = $1; }
725         |
726         INTEGER { $$ = $1; }
727         |
728         FLOAT { $$ = $1; }
729         |
730         datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
731         |
732         interval { $$ = $1; }
733         |
734         array { $$ = $1; }
735         ;
737 datetime:
738         DATE TIME { $$ = $1 + $2; }
739         |
740         DATE { $$ = $1; }
741         |
742         TIME { $$ = $1; }
743         ;
745 interval:
746         interval interval_elem
747                 {
748                         $$.data.datetime = $1.data.datetime + $2.data.datetime;
749                 }
750         |
751         interval_elem { $$ = $1; }
752         ;
754 interval_elem:
755         INTEGER IDENTIFIER
756                 {
757                         sdb_time_t unit = 1;
759                         unit = sdb_strpunit($2);
760                         if (! unit) {
761                                 sdb_fe_yyerrorf(&yylloc, scanner,
762                                                 YY_("syntax error, invalid time unit %s"), $2);
763                                 free($2); $2 = NULL;
764                                 YYABORT;
765                         }
766                         free($2); $2 = NULL;
768                         $$.type = SDB_TYPE_DATETIME;
769                         $$.data.datetime = (sdb_time_t)$1.data.integer * unit;
771                         if ($1.data.integer < 0) {
772                                 sdb_fe_yyerror(&yylloc, scanner,
773                                                 YY_("syntax error, negative intervals not supported"));
774                                 YYABORT;
775                         }
776                 }
777         ;
779 array:
780         '[' array_elem_list ']'
781                 {
782                         $$ = $2;
783                 }
784         ;
786 array_elem_list:
787         array_elem_list ',' data
788                 {
789                         size_t elem_size;
791                         if (($3.type & SDB_TYPE_ARRAY) || (($1.type & 0xff) != $3.type)) {
792                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
793                                                 "cannot use element of type %s in array of type %s"),
794                                                 SDB_TYPE_TO_STRING($3.type),
795                                                 SDB_TYPE_TO_STRING($1.type));
796                                 sdb_data_free_datum(&$1);
797                                 sdb_data_free_datum(&$3);
798                                 YYABORT;
799                         }
801                         elem_size = sdb_data_sizeof($3.type);
802                         $1.data.array.values = realloc($1.data.array.values,
803                                         ($1.data.array.length + 1) * elem_size);
804                         if (! $1.data.array.values) {
805                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
806                                 YYABORT;
807                         }
809                         memcpy((char *)$1.data.array.values
810                                                 + $1.data.array.length * elem_size,
811                                         &$3.data, elem_size);
812                         ++$1.data.array.length;
814                         $$ = $1;
815                 }
816         |
817         data
818                 {
819                         size_t elem_size;
821                         if ($1.type & SDB_TYPE_ARRAY) {
822                                 sdb_fe_yyerrorf(&yylloc, scanner, YY_("syntax error, "
823                                                 "cannot construct array of type %s"),
824                                                 SDB_TYPE_TO_STRING($1.type));
825                                 sdb_data_free_datum(&$1);
826                                 YYABORT;
827                         }
829                         $$ = $1;
830                         $$.type = $1.type | SDB_TYPE_ARRAY;
831                         $$.data.array.length = 1;
832                         elem_size = sdb_data_sizeof($1.type);
833                         $$.data.array.values = malloc(elem_size);
834                         if (! $$.data.array.values ) {
835                                 sdb_fe_yyerror(&yylloc, scanner, YY_("out of memory"));
836                                 YYABORT;
837                         }
838                         memcpy($$.data.array.values, &$1.data, elem_size);
839                 }
840         ;
842 %%
844 void
845 sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg)
847         sdb_log(SDB_LOG_ERR, "frontend: parse error: %s", msg);
848         sdb_strbuf_sprintf(errbuf, "%s", msg);
849 } /* sdb_fe_yyerror */
851 void
852 sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...)
854         va_list ap, aq;
855         va_start(ap, fmt);
856         va_copy(aq, ap);
857         sdb_vlog(SDB_LOG_ERR, fmt, ap);
858         sdb_strbuf_vsprintf(errbuf, fmt, aq);
859         va_end(ap);
860 } /* sdb_fe_yyerrorf */
862 static sdb_store_matcher_t *
863 name_iter_matcher(int type, sdb_store_expr_t *iter, const char *cmp,
864                 sdb_store_expr_t *expr)
866         sdb_store_matcher_op_cb cb = sdb_store_parse_matcher_op(cmp);
867         sdb_store_matcher_t *m, *tmp = NULL;
868         assert(cb);
870         m = cb(NULL, expr);
871         if (type == MATCHER_ANY)
872                 tmp = sdb_store_any_matcher(iter, m);
873         else if (type == MATCHER_ALL)
874                 tmp = sdb_store_all_matcher(iter, m);
875         sdb_object_deref(SDB_OBJ(m));
876         return tmp;
877 } /* name_iter_matcher */
879 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */