Code

frontend: Added support for array constants.
authorSebastian Harl <sh@tokkee.org>
Wed, 12 Nov 2014 21:10:47 +0000 (22:10 +0100)
committerSebastian Harl <sh@tokkee.org>
Wed, 12 Nov 2014 21:10:47 +0000 (22:10 +0100)
src/frontend/analyzer.c
src/frontend/grammar.y
t/unit/core/store_lookup_test.c
t/unit/frontend/parser_test.c

index c1b9d01ef19494188dddd2d3dd916601715e924a..2de9befa6eeb6605ca405fb07689f6672c86b169 100644 (file)
@@ -165,6 +165,10 @@ analyze_matcher(int context, sdb_store_matcher_t *m, sdb_strbuf_t *errbuf)
                case MATCHER_GE:
                case MATCHER_GT:
                        assert(CMP_M(m)->left && CMP_M(m)->right);
+                       if ((CMP_M(m)->left->data_type > 0)
+                                       && (CMP_M(m)->right->data_type > 0)
+                                       && (CMP_M(m)->left->data_type == CMP_M(m)->right->data_type))
+                               return 0;
                        if ((CMP_M(m)->left->data_type > 0)
                                        && (CMP_M(m)->left->data_type & SDB_TYPE_ARRAY)) {
                                cmp_error(errbuf, m->type, CMP_M(m)->left->data_type,
index 80fb249684e0120be85cd421905fec666d277bc4..d4e54a9c4c8f3869946bfa151de5d764c1156e88 100644 (file)
@@ -171,6 +171,7 @@ sdb_fe_yyerrorf(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *fmt, ...);
 
 %type <data> data
        interval interval_elem
+       array array_elem_list
 
 %type <datetime> datetime
        start_clause end_clause
@@ -599,6 +600,8 @@ data:
        datetime { $$.type = SDB_TYPE_DATETIME; $$.data.datetime = $1; }
        |
        interval { $$ = $1; }
+       |
+       array { $$ = $1; }
        ;
 
 datetime:
@@ -626,7 +629,7 @@ interval_elem:
                        unit = sdb_strpunit($2);
                        if (! unit) {
                                sdb_fe_yyerrorf(&yylloc, scanner,
-                                               YY_("invalid time unit %s"), $2);
+                                               YY_("syntax error, invalid time unit %s"), $2);
                                free($2); $2 = NULL;
                                YYABORT;
                        }
@@ -643,6 +646,69 @@ interval_elem:
                }
        ;
 
+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);
+               }
+       ;
+
 %%
 
 void
index 18d811f0201edac5fd3a3ebc75d4f5951b981c65..49f9125647dafbd17fa630278f749a1d630aa03b 100644 (file)
@@ -534,6 +534,12 @@ START_TEST(test_scan)
                { "name =~ '.'", NULL,                 3 },
                { "ANY backend = 'backend'", NULL,     0 },
                { "ALL backend = ''", NULL,            3 }, /* backend is empty */
+               { "backend = ['backend']", NULL,       0 },
+               { "backend != ['backend']", NULL,      3 },
+               { "backend < ['backend']", NULL,       3 },
+               { "backend <= ['backend']", NULL,      3 },
+               { "backend >= ['backend']", NULL,      0 },
+               { "backend > ['backend']", NULL,       0 },
                { "ANY metric = 'm1'", NULL,           2 },
                { "ANY metric= 'm1'", "name = 'x'",    0 }, /* filter never matches */
                { "ANY metric = 'm1'",
index 17c1032bcd0168c94fb9a9ae5873d111c6eb3926..c377f78fa59a9acd359de8fdeb560fce0013ce52 100644 (file)
@@ -186,6 +186,12 @@ START_TEST(test_parse)
                  "1Y42D",               -1,  1, CONNECTION_LOOKUP },
                 */
 
+               /* array constants */
+               { "LOOKUP hosts MATCHING "
+                 "backend = ['foo']",   -1,  1, CONNECTION_LOOKUP },
+               { "LOOKUP hosts MATCHING "
+                 "backend = ['a','b']", -1,  1, CONNECTION_LOOKUP },
+
                /* NULL */
                { "LOOKUP hosts MATCHING "
                  "attribute['foo'] "
@@ -452,6 +458,14 @@ START_TEST(test_parse_matcher)
                 * IS NULL currently maps to an equality matcher */
                { "attribute['foo'] IS NULL",     -1,  MATCHER_ISNULL },
                { "attribute['foo'] IS NOT NULL", -1,  MATCHER_ISNNULL },
+               /* array expressions */
+               { "backend < ['a']",              -1,  MATCHER_LT },
+               { "backend <= ['a']",             -1,  MATCHER_LE },
+               { "backend = ['a']",              -1,  MATCHER_EQ },
+               { "backend != ['a']",             -1,  MATCHER_NE },
+               { "backend >= ['a']",             -1,  MATCHER_GE },
+               { "backend > ['a']",              -1,  MATCHER_GT },
+               { "backend &^ ['a']",             -1,  -1 },
 
                /* object field matchers */
                { "name < 'a'",                   -1,  MATCHER_LT },