Code

parser: Determine the data-type of each node.
authorSebastian Harl <sh@tokkee.org>
Tue, 5 May 2015 21:52:41 +0000 (23:52 +0200)
committerSebastian Harl <sh@tokkee.org>
Tue, 5 May 2015 21:52:41 +0000 (23:52 +0200)
For now, we only use this for arithmetic expressions. The field will be
populated by the analyzer.

src/include/parser/ast.h
src/parser/analyzer.c

index 2ae2912b741884ed7ee2db8e7fa42f077756f8f5..41fb2179e805e5c1bbd9ea1e3a591b1a685735ae 100644 (file)
@@ -166,6 +166,9 @@ typedef struct {
 
        /* type describes the type of the actual node */
        int type;
+
+       /* data-type describes the type of the result value */
+       int data_type;
 } sdb_ast_node_t;
 #define SDB_AST_NODE(obj) ((sdb_ast_node_t *)(obj))
 
@@ -181,7 +184,7 @@ typedef struct {
 } sdb_ast_op_t;
 #define SDB_AST_OP(obj) ((sdb_ast_op_t *)(obj))
 #define SDB_AST_OP_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_OPERATOR }, -1, NULL, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_OPERATOR, -1 }, -1, NULL, NULL }
 
 /*
  * sdb_ast_iter_t represents an iterator.
@@ -196,7 +199,7 @@ typedef struct {
 } sdb_ast_iter_t;
 #define SDB_AST_ITER(obj) ((sdb_ast_iter_t *)(obj))
 #define SDB_AST_ITER_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_ITERATOR }, -1, NULL, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_ITERATOR, -1 }, -1, NULL, NULL }
 
 /*
  * sdb_ast_typed_t represents a typed value.
@@ -208,7 +211,7 @@ typedef struct {
 } sdb_ast_typed_t;
 #define SDB_AST_TYPED(obj) ((sdb_ast_typed_t *)(obj))
 #define SDB_AST_TYPED_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_TYPED }, -1, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_TYPED, -1 }, -1, NULL }
 
 /*
  * sdb_ast_const_t represents a constant value.
@@ -219,7 +222,7 @@ typedef struct {
 } sdb_ast_const_t;
 #define SDB_AST_CONST(obj) ((sdb_ast_const_t *)(obj))
 #define SDB_AST_CONST_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_CONST }, SDB_DATA_INIT }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_CONST, -1 }, SDB_DATA_INIT }
 
 /*
  * sdb_ast_value_t represents an object-specific value: sibling nodes,
@@ -232,7 +235,7 @@ typedef struct {
 } sdb_ast_value_t;
 #define SDB_AST_VALUE(obj) ((sdb_ast_value_t *)(obj))
 #define SDB_AST_VALUE_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_VALUE }, -1, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_VALUE, -1 }, -1, NULL }
 
 /*
  * sdb_ast_fetch_t represents a FETCH command.
@@ -246,7 +249,7 @@ typedef struct {
 } sdb_ast_fetch_t;
 #define SDB_AST_FETCH(obj) ((sdb_ast_fetch_t *)(obj))
 #define SDB_AST_FETCH_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH }, -1, NULL, NULL, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_FETCH, -1 }, -1, NULL, NULL, NULL }
 
 /*
  * sdb_ast_list_t represents a LIST command.
@@ -258,7 +261,7 @@ typedef struct {
 } sdb_ast_list_t;
 #define SDB_AST_LIST(obj) ((sdb_ast_list_t *)(obj))
 #define SDB_AST_LIST_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_LIST }, -1, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_LIST, -1 }, -1, NULL }
 
 /*
  * sdb_ast_lookup_t represents a LOOKUP command.
@@ -271,7 +274,7 @@ typedef struct {
 } sdb_ast_lookup_t;
 #define SDB_AST_LOOKUP(obj) ((sdb_ast_lookup_t *)(obj))
 #define SDB_AST_LOOKUP_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_LOOKUP }, -1, NULL, NULL }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_LOOKUP, -1 }, -1, NULL, NULL }
 
 /*
  * sdb_ast_store_t represents a STORE command.
@@ -294,7 +297,7 @@ typedef struct {
 } sdb_ast_store_t;
 #define SDB_AST_STORE(obj) ((sdb_ast_store_t *)(obj))
 #define SDB_AST_STORE_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_STORE }, \
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_STORE, -1 }, \
                -1, NULL, -1, NULL, NULL, 0, NULL, NULL, SDB_DATA_INIT }
 
 /*
@@ -309,7 +312,7 @@ typedef struct {
 } sdb_ast_timeseries_t;
 #define SDB_AST_TIMESERIES(obj) ((sdb_ast_timeseries_t *)(obj))
 #define SDB_AST_TIMESERIES_INIT \
-       { { SDB_OBJECT_INIT, SDB_AST_TYPE_TIMESERIES }, NULL, NULL, 0, 0 }
+       { { SDB_OBJECT_INIT, SDB_AST_TYPE_TIMESERIES, -1 }, NULL, NULL, 0, 0 }
 
 /*
  * AST constructors:
index 244966b9a651b4ad9c72a67fbedb5375d2ea7352..79c99e3e23e159ae8217a7dec323bf946c8d7e9b 100644 (file)
 
 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
 
+static int
+analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
+
 /*
- * private helper functions
+ * expression nodes
  */
 
+static int
+analyze_logical(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
+{
+       switch (op->kind) {
+       case SDB_AST_OR:
+       case SDB_AST_AND:
+               if (analyze_node(context, op->left, errbuf))
+                       return -1;
+               /* fallthrough */
+       case SDB_AST_NOT:
+               if (analyze_node(context, op->right, errbuf))
+                       return -1;
+               break;
+
+       case SDB_AST_LT:
+       case SDB_AST_LE:
+       case SDB_AST_EQ:
+       case SDB_AST_NE:
+       case SDB_AST_GE:
+       case SDB_AST_GT:
+       {
+               if (analyze_node(context, op->left, errbuf))
+                       return -1;
+               if (analyze_node(context, op->right, errbuf))
+                       return -1;
+               break;
+       }
+
+       case SDB_AST_REGEX:
+       case SDB_AST_NREGEX:
+               if (analyze_node(context, op->left, errbuf))
+                       return -1;
+               if (analyze_node(context, op->right, errbuf))
+                       return -1;
+               break;
+
+       case SDB_AST_ISNULL:
+               if (analyze_node(context, op->right, errbuf))
+                       return -1;
+               break;
+
+       case SDB_AST_IN:
+               if (analyze_node(context, op->left, errbuf))
+                       return -1;
+               if (analyze_node(context, op->right, errbuf))
+                       return -1;
+               break;
+
+       default:
+               sdb_strbuf_sprintf(errbuf, "Unknown matcher type %d", op->kind);
+               return -1;
+       }
+       return 0;
+} /* analyze_logical */
+
+static int
+analyze_arith(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
+{
+       if (analyze_node(context, op->left, errbuf))
+               return -1;
+       if (analyze_node(context, op->right, errbuf))
+               return -1;
+       SDB_AST_NODE(op)->data_type = sdb_data_expr_type(op->kind,
+                       op->left->data_type, op->right->data_type);
+
+       /* TODO: replace constant arithmetic operations with a constant value */
+       return 0;
+} /* analyze_arith */
+
+static int
+analyze_iter(int context, sdb_ast_iter_t *iter, sdb_strbuf_t *errbuf)
+{
+       sdb_ast_const_t c = SDB_AST_CONST_INIT;
+       int status;
+
+       if (analyze_node(context, iter->iter, errbuf))
+               return -1;
+       c.super.data_type = iter->iter->data_type;
+
+       /* TODO: support other setups as well */
+       assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
+                       && (! SDB_AST_OP(iter->expr)->left));
+       SDB_AST_OP(iter->expr)->left = SDB_AST_NODE(&c);
+       status = analyze_node(context, iter->expr, errbuf);
+       SDB_AST_OP(iter->expr)->left = NULL;
+       if (status)
+               return -1;
+       return 0;
+} /* analyze_iter */
+
+static int
+analyze_const(int __attribute__((unused)) context, sdb_ast_const_t *c,
+               sdb_strbuf_t __attribute__((unused)) *errbuf)
+{
+       SDB_AST_NODE(c)->data_type = c->value.type;
+       return 0;
+} /* analyze_const */
+
+static int
+analyze_value(int __attribute__((unused)) context, sdb_ast_value_t *v,
+               sdb_strbuf_t __attribute__((unused)) *errbuf)
+{
+       if (v->type != SDB_ATTRIBUTE)
+               SDB_AST_NODE(v)->data_type = SDB_FIELD_TYPE(v->type);
+       return 0;
+} /* analyze_value */
+
+static int
+analyze_typed(int __attribute__((unused)) context, sdb_ast_typed_t *t,
+               sdb_strbuf_t *errbuf)
+{
+       if (analyze_node(t->type, t->expr, errbuf))
+               return -1;
+       SDB_AST_NODE(t)->data_type = t->expr->data_type;
+       return 0;
+} /* analyze_typed */
+
 static int
 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
 {
-       (void)context;
        if (! node) {
                sdb_strbuf_sprintf(errbuf, "Empty AST node");
                return -1;
        }
-       return 0;
+
+       /* unknown by default */
+       node->data_type = -1;
+
+       if ((node->type == SDB_AST_TYPE_OPERATOR)
+                       && (SDB_AST_IS_LOGICAL(node)))
+               return analyze_logical(context, SDB_AST_OP(node), errbuf);
+       else if ((node->type == SDB_AST_TYPE_OPERATOR)
+                       && (SDB_AST_IS_ARITHMETIC(node)))
+               return analyze_arith(context, SDB_AST_OP(node), errbuf);
+       else if (node->type == SDB_AST_TYPE_ITERATOR)
+               return analyze_iter(context, SDB_AST_ITER(node), errbuf);
+       else if (node->type == SDB_AST_TYPE_CONST)
+               return analyze_const(context, SDB_AST_CONST(node), errbuf);
+       else if (node->type == SDB_AST_TYPE_VALUE)
+               return analyze_value(context, SDB_AST_VALUE(node), errbuf);
+       else if (node->type == SDB_AST_TYPE_TYPED)
+               return analyze_typed(context, SDB_AST_TYPED(node), errbuf);
+
+       sdb_strbuf_sprintf(errbuf, "Invalid expression node "
+                       "of type %#x", node->type);
+       return -1;
 } /* analyze_node */
 
 /*
@@ -84,7 +224,7 @@ analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
        if (fetch->filter)
                return analyze_node(-1, fetch->filter, errbuf);
        return 0;
-}
+} /* analyze_fetch */
 
 static int
 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
@@ -97,7 +237,7 @@ analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
        if (list->filter)
                return analyze_node(-1, list->filter, errbuf);
        return 0;
-}
+} /* analyze_list */
 
 static int
 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
@@ -113,7 +253,7 @@ analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
        if (lookup->filter)
                return analyze_node(-1, lookup->filter, errbuf);
        return 0;
-}
+} /* analyze_lookup */
 
 static int
 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
@@ -201,7 +341,7 @@ analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
                return -1;
        }
        return 0;
-}
+} /* analyze_store */
 
 static int
 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
@@ -223,7 +363,7 @@ analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
                return -1;
        }
        return 0;
-}
+} /* analyze_timeseries */
 
 /*
  * public API
@@ -237,6 +377,9 @@ sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
                return -1;
        }
 
+       /* top-level nodes don't have a type */
+       node->data_type = -1;
+
        if (node->type == SDB_AST_TYPE_FETCH)
                return analyze_fetch(SDB_AST_FETCH(node), errbuf);
        else if (node->type == SDB_AST_TYPE_LIST)
@@ -251,7 +394,7 @@ sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
        sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
                        "of type %#x", node->type);
        return -1;
-} /* sdb_fe_analyze */
+} /* sdb_parser_analyze */
 
 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */