From: Sebastian Harl Date: Tue, 5 May 2015 22:15:49 +0000 (+0200) Subject: parser: Add support for analyzing conditional and arithmetic expressions. X-Git-Tag: sysdb-0.8.0~105 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=195f73cdb0c1087bf3f3a82267204fca9eb3104c;ds=sidebyside parser: Add support for analyzing conditional and arithmetic expressions. Let all parser functions call the respective analyzer. For now, this is only used to propagate data-type information but it will later ensure a certain amount of semantical correctness. Note that the new analyzers usually don't have any context information, so they might accept expressions that are not right for their later target use case. If that matters, the caller will have to check again providing the right context. --- diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 0a7c720..92e49bb 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -84,6 +84,30 @@ sdb_parser_parse_arith(const char *expr, int len, sdb_strbuf_t *errbuf); int sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf); +/* + * sdb_parser_analyze_conditional: + * Semantical analysis of a conditional node. + * + * Returns: + * - 0 on success + * - a negative value else; an error message will be written to the provided + * error buffer + */ +int +sdb_parser_analyze_conditional(sdb_ast_node_t *node, sdb_strbuf_t *errbuf); + +/* + * sdb_parser_analyze_arith: + * Semantical analysis of an arithmetic node. + * + * Returns: + * - 0 on success + * - a negative value else; an error message will be written to the provided + * error buffer + */ +int +sdb_parser_analyze_arith(sdb_ast_node_t *node, sdb_strbuf_t *errbuf); + /* * Low-level interface. */ diff --git a/src/parser/analyzer.c b/src/parser/analyzer.c index 7193fea..867af52 100644 --- a/src/parser/analyzer.c +++ b/src/parser/analyzer.c @@ -396,5 +396,35 @@ sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf) return -1; } /* sdb_parser_analyze */ +int +sdb_parser_analyze_conditional(sdb_ast_node_t *node, sdb_strbuf_t *errbuf) +{ + if (! node) { + sdb_strbuf_sprintf(errbuf, "Empty conditional node"); + return -1; + } + if (! SDB_AST_IS_LOGICAL(node)) { + sdb_strbuf_sprintf(errbuf, "Not a conditional node (got %s)", + SDB_AST_TYPE_TO_STRING(node)); + return -1; + } + return analyze_node(-1, node, errbuf); +} /* sdb_parser_analyze_conditional */ + +int +sdb_parser_analyze_arith(sdb_ast_node_t *node, sdb_strbuf_t *errbuf) +{ + if (! node) { + sdb_strbuf_sprintf(errbuf, "Empty arithmetic node"); + return -1; + } + if (! SDB_AST_IS_ARITHMETIC(node)) { + sdb_strbuf_sprintf(errbuf, "Not an arithmetic node (got %s)", + SDB_AST_TYPE_TO_STRING(node)); + return -1; + } + return analyze_node(-1, node, errbuf); +} /* sdb_parser_analyze_arith */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/parser/parser.c b/src/parser/parser.c index de6085f..e3073a9 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -140,6 +140,11 @@ sdb_parser_parse_conditional(const char *cond, int len, sdb_strbuf_t *errbuf) assert(SDB_AST_IS_LOGICAL(node)); sdb_llist_destroy(yyextra.parsetree); + + if (sdb_parser_analyze_conditional(node, errbuf)) { + sdb_object_deref(SDB_OBJ(node)); + return NULL; + } return node; } /* sdb_parser_parse_conditional */ @@ -175,6 +180,11 @@ sdb_parser_parse_arith(const char *expr, int len, sdb_strbuf_t *errbuf) assert(SDB_AST_IS_ARITHMETIC(node)); sdb_llist_destroy(yyextra.parsetree); + + if (sdb_parser_analyze_arith(node, errbuf)) { + sdb_object_deref(SDB_OBJ(node)); + return NULL; + } return node; } /* sdb_parser_parse_arith */ diff --git a/t/unit/parser/parser_test.c b/t/unit/parser/parser_test.c index ad9f8f9..68e1527 100644 --- a/t/unit/parser/parser_test.c +++ b/t/unit/parser/parser_test.c @@ -900,6 +900,11 @@ START_TEST(test_parse_conditional) "expected: %d", parse_conditional_data[_i].expr, SDB_AST_ITER(node)->kind, parse_conditional_data[_i].expected); + fail_unless(node->data_type == -1, + "sdb_parser_parse_conditional(%s) returned conditional of data-type %s; " + "expected: %s", parse_conditional_data[_i].expr, + SDB_TYPE_TO_STRING(node->data_type), SDB_TYPE_TO_STRING(-1)); + sdb_object_deref(SDB_OBJ(node)); sdb_strbuf_destroy(errbuf); } @@ -909,63 +914,64 @@ struct { const char *expr; int len; int expected; + int data_type; } parse_arith_data[] = { /* empty expressions */ - { NULL, -1, -1 }, - { "", -1, -1 }, + { NULL, -1, -1, -1 }, + { "", -1, -1, -1 }, /* constant expressions */ - { "'localhost'", -1, SDB_AST_TYPE_CONST }, - { "123", -1, SDB_AST_TYPE_CONST }, - { "2014-08-16", -1, SDB_AST_TYPE_CONST }, - { "17:23", -1, SDB_AST_TYPE_CONST }, - { "17:23:53", -1, SDB_AST_TYPE_CONST }, - { "17:23:53.123", -1, SDB_AST_TYPE_CONST }, - { "17:23:53.123456789", -1, SDB_AST_TYPE_CONST }, - { "2014-08-16 17:23", -1, SDB_AST_TYPE_CONST }, - { "2014-08-16 17:23:53", -1, SDB_AST_TYPE_CONST }, - { "10s", -1, SDB_AST_TYPE_CONST }, - { "60m", -1, SDB_AST_TYPE_CONST }, - { "10Y 24D 1h", -1, SDB_AST_TYPE_CONST }, + { "'localhost'", -1, SDB_AST_TYPE_CONST, SDB_TYPE_STRING }, + { "123", -1, SDB_AST_TYPE_CONST, SDB_TYPE_INTEGER }, + { "42.3", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DECIMAL }, + { "2014-08-16", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "17:23", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "17:23:53", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "17:23:53.123", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "17:23:53.123456789", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "2014-08-16 17:23", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "2014-08-16 17:23:53", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "10s", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "60m", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, + { "10Y 24D 1h", -1, SDB_AST_TYPE_CONST, SDB_TYPE_DATETIME }, /* TODO: the analyzer and/or optimizer should turn these into constants */ - { "123 + 456", -1, SDB_AST_ADD }, - { "'foo' || 'bar'", -1, SDB_AST_CONCAT }, - { "456 - 123", -1, SDB_AST_SUB }, - { "1.2 * 3.4", -1, SDB_AST_MUL }, - { "1.2 / 3.4", -1, SDB_AST_DIV }, - { "5 % 2", -1, SDB_AST_MOD }, + { "123 + 456", -1, SDB_AST_ADD, SDB_TYPE_INTEGER }, + { "'foo' || 'bar'", -1, SDB_AST_CONCAT, SDB_TYPE_STRING }, + { "456 - 123", -1, SDB_AST_SUB, SDB_TYPE_INTEGER }, + { "1.2 * 3.4", -1, SDB_AST_MUL, SDB_TYPE_DECIMAL }, + { "1.2 / 3.4", -1, SDB_AST_DIV, SDB_TYPE_DECIMAL }, + { "5 % 2", -1, SDB_AST_MOD, SDB_TYPE_INTEGER }, /* queryable fields */ - { "last_update", -1, SDB_AST_TYPE_VALUE }, - { "AGE", -1, SDB_AST_TYPE_VALUE }, - { "interval", -1, SDB_AST_TYPE_VALUE }, - { "Last_Update", -1, SDB_AST_TYPE_VALUE }, - { "backend", -1, SDB_AST_TYPE_VALUE }, + { "last_update", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME }, + { "AGE", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME }, + { "interval", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME }, + { "Last_Update", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_DATETIME }, + { "backend", -1, SDB_AST_TYPE_VALUE, SDB_TYPE_ARRAY | SDB_TYPE_STRING }, /* attributes */ - { "attribute['foo']", -1, SDB_AST_TYPE_VALUE }, + { "attribute['foo']", -1, SDB_AST_TYPE_VALUE, -1 }, /* arithmetic expressions */ - { "age + age", -1, SDB_AST_ADD }, - { "age - age", -1, SDB_AST_SUB }, - { "age * age", -1, SDB_AST_MUL }, - { "age / age", -1, SDB_AST_DIV }, - { "age \% age", -1, SDB_AST_MOD }, - { "age || age", -1, SDB_AST_CONCAT }, + { "age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME }, + { "age - age", -1, SDB_AST_SUB, SDB_TYPE_DATETIME }, + { "age * age", -1, SDB_AST_MUL, SDB_TYPE_DATETIME }, + { "age / age", -1, SDB_AST_DIV, SDB_TYPE_DATETIME }, + { "age \% age", -1, SDB_AST_MOD, SDB_TYPE_DATETIME }, /* operator precedence */ - { "age + age * age", -1, SDB_AST_ADD }, - { "age * age + age", -1, SDB_AST_ADD }, - { "age + age - age", -1, SDB_AST_SUB }, - { "age - age + age", -1, SDB_AST_ADD }, - { "(age + age) * age", -1, SDB_AST_MUL }, - { "age + (age * age)", -1, SDB_AST_ADD }, + { "age + age * age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME }, + { "age * age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME }, + { "age + age - age", -1, SDB_AST_SUB, SDB_TYPE_DATETIME }, + { "age - age + age", -1, SDB_AST_ADD, SDB_TYPE_DATETIME }, + { "(age + age) * age", -1, SDB_AST_MUL, SDB_TYPE_DATETIME }, + { "age + (age * age)", -1, SDB_AST_ADD, SDB_TYPE_DATETIME }, /* syntax errors */ - { "LIST", -1, -1 }, - { "foo &^ bar", -1, -1 }, - { "invalid", -1, -1 }, + { "LIST", -1, -1, -1 }, + { "foo &^ bar", -1, -1, -1 }, + { "invalid", -1, -1, -1 }, }; START_TEST(test_parse_arith) @@ -999,6 +1005,12 @@ START_TEST(test_parse_arith) "expected: %d", parse_arith_data[_i].expr, node->type, parse_arith_data[_i].expected); + fail_unless(node->data_type == parse_arith_data[_i].data_type, + "sdb_parser_parse_arith(%s) returned expression of data-type %s; " + "expected: %s", parse_arith_data[_i].expr, + SDB_TYPE_TO_STRING(node->data_type), + SDB_TYPE_TO_STRING(parse_arith_data[_i].data_type)); + sdb_object_deref(SDB_OBJ(node)); sdb_strbuf_destroy(errbuf); }