Code

parser/ast: Introduce a data-structure representing a SysQL AST.
authorSebastian Harl <sh@tokkee.org>
Sun, 12 Apr 2015 12:45:49 +0000 (14:45 +0200)
committerSebastian Harl <sh@tokkee.org>
Sun, 12 Apr 2015 12:45:49 +0000 (14:45 +0200)
This will be used by the parser in the future.

src/Makefile.am
src/include/parser/ast.h [new file with mode: 0644]
src/parser/ast.c [new file with mode: 0644]

index ddd856cd6b8e858b936132d27a617a67025b58e6..a7f6c9b73744c4f27dade47960386a7bea35a110 100644 (file)
@@ -91,6 +91,7 @@ libsysdb_la_SOURCES = \
                frontend/session.c \
                frontend/store.c \
                frontend/query.c \
                frontend/session.c \
                frontend/store.c \
                frontend/query.c \
+               parser/ast.c include/parser/ast.h \
                utils/avltree.c include/utils/avltree.h \
                utils/channel.c include/utils/channel.h \
                utils/error.c include/utils/error.h \
                utils/avltree.c include/utils/avltree.h \
                utils/channel.c include/utils/channel.h \
                utils/error.c include/utils/error.h \
diff --git a/src/include/parser/ast.h b/src/include/parser/ast.h
new file mode 100644 (file)
index 0000000..3bdc5b6
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * SysDB - src/include/parser/ast.h
+ * Copyright (C) 2013-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The SysDB query language AST describes the parse-tree of an SysQL query.
+ */
+
+#ifndef SDB_PARSER_AST_H
+#define SDB_PARSER_AST_H 1
+
+#include "core/data.h"
+#include "core/time.h"
+#include "core/object.h"
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * sdb_ast_node_type_t describes the type of an AST node.
+ */
+typedef enum {
+       /* command nodes */
+       SDB_AST_TYPE_FETCH      = 1,
+       SDB_AST_TYPE_LIST       = 2,
+       SDB_AST_TYPE_LOOKUP     = 3,
+       SDB_AST_TYPE_STORE      = 4,
+       SDB_AST_TYPE_TIMESERIES = 5,
+
+       /* generic expressions */
+       SDB_AST_TYPE_OPERATOR   = 100,
+       SDB_AST_TYPE_ITERATOR   = 101,
+
+       /* values */
+       SDB_AST_TYPE_CONST      = 200,
+       SDB_AST_TYPE_VALUE      = 201,
+
+       SDB_AST_TYPE_TYPED      = 210,
+} sdb_ast_node_type_t;
+
+/*
+ * sdb_ast_operator_t describes the type of an operator.
+ */
+typedef enum {
+       /* logical and comparison operators */
+#define SDB_AST_IS_LOGICAL(n) \
+       ((((n)->type == SDB_AST_TYPE_OPERATOR) \
+                       && ((SDB_AST_AND <= SDB_AST_OP(n)->kind) \
+                               && (SDB_AST_OP(n)->kind <= SDB_AST_IN))) \
+               || (((n)->type == SDB_AST_TYPE_ITERATOR) \
+                       && ((SDB_AST_ALL <= SDB_AST_ITER(n)->kind) \
+                               && (SDB_AST_ITER(n)->kind <= SDB_AST_ANY))))
+       SDB_AST_AND    = 1000,
+       SDB_AST_OR     = 1001,
+       SDB_AST_NOT    = 1002,
+
+       SDB_AST_LT     = 1010,
+       SDB_AST_LE     = 1011,
+       SDB_AST_EQ     = 1012,
+       SDB_AST_NE     = 1013,
+       SDB_AST_GE     = 1014,
+       SDB_AST_GT     = 1015,
+       SDB_AST_REGEX  = 1016,
+       SDB_AST_NREGEX = 1017,
+       SDB_AST_ISNULL = 1018,
+       SDB_AST_IN     = 1019,
+
+       /* arithmetic expressions */
+#define SDB_AST_IS_ARITHMETIC(n) \
+       (((n)->type == SDB_AST_TYPE_CONST) \
+               || ((n)->type == SDB_AST_TYPE_VALUE) \
+               || ((n)->type == SDB_AST_TYPE_TYPED) \
+               || (((n)->type == SDB_AST_TYPE_OPERATOR) \
+                       && ((SDB_AST_ADD <= SDB_AST_OP(n)->kind) \
+                               && (SDB_AST_OP(n)->kind <= SDB_AST_CONCAT))))
+       SDB_AST_ADD    = 2000,
+       SDB_AST_SUB    = 2001,
+       SDB_AST_MUL    = 2002,
+       SDB_AST_DIV    = 2003,
+       SDB_AST_MOD    = 2004,
+       SDB_AST_CONCAT = 2005,
+
+       /* iterators */
+       SDB_AST_ALL    = 3000,
+       SDB_AST_ANY    = 3001,
+} sdb_ast_operator_t;
+
+#define SDB_AST_OP_TO_STRING(op) \
+       (((op) == SDB_AST_AND) ? "AND" \
+               : ((op) == SDB_AST_OR) ? "OR" \
+               : ((op) == SDB_AST_NOT) ? "NOT" \
+               : ((op) == SDB_AST_LT) ? "LT" \
+               : ((op) == SDB_AST_LE) ? "LE" \
+               : ((op) == SDB_AST_EQ) ? "EQ" \
+               : ((op) == SDB_AST_NE) ? "NE" \
+               : ((op) == SDB_AST_GE) ? "GE" \
+               : ((op) == SDB_AST_GT) ? "GT" \
+               : ((op) == SDB_AST_REGEX) ? "REGEX" \
+               : ((op) == SDB_AST_NREGEX) ? "NREGEX" \
+               : ((op) == SDB_AST_ISNULL) ? "ISNULL" \
+               : ((op) == SDB_AST_IN) ? "IN" \
+               : ((op) == SDB_AST_ADD) ? "ADD" \
+               : ((op) == SDB_AST_SUB) ? "SUB" \
+               : ((op) == SDB_AST_MUL) ? "MUL" \
+               : ((op) == SDB_AST_DIV) ? "DIV" \
+               : ((op) == SDB_AST_MOD) ? "MOD" \
+               : ((op) == SDB_AST_CONCAT) ? "CONCAT" \
+               : ((op) == SDB_AST_ALL) ? "ALL" \
+               : ((op) == SDB_AST_ANY) ? "ANY" \
+               : "UNKNOWN")
+
+/*
+ * sdb_ast_node_t is the interface for AST nodes. The first field of any
+ * actual implementation of the interface is of type sdb_ast_node_t to
+ * fascilitate casting between the interface and implementation types.
+ *
+ * It inherits from sdb_object_t and instances may safely be cast to a generic
+ * object as well.
+ */
+typedef struct {
+       sdb_object_t super;
+
+       /* type describes the type of the actual node */
+       int type;
+} sdb_ast_node_t;
+#define SDB_AST_NODE(obj) ((sdb_ast_node_t *)(obj))
+
+/*
+ * sdb_ast_op_t represents a simple operation.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int kind;
+       /* left operand is NULL for unary expressions */
+       sdb_ast_node_t *left;
+       sdb_ast_node_t *right;
+} sdb_ast_op_t;
+#define SDB_AST_OP(obj) ((sdb_ast_op_t *)(obj))
+
+/*
+ * sdb_ast_iter_t represents an iterator.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int kind;
+       int op;
+       sdb_ast_node_t *iter;
+       /* exactly one operand of the expression has to be unset and will be
+        * filled in by the iterator value */
+       sdb_ast_node_t *expr;
+} sdb_ast_iter_t;
+#define SDB_AST_ITER(obj) ((sdb_ast_iter_t *)(obj))
+
+/*
+ * sdb_ast_typed_t represents a typed value.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int type;
+       sdb_ast_node_t *expr;
+} sdb_ast_typed_t;
+#define SDB_AST_TYPED(obj) ((sdb_ast_typed_t *)(obj))
+
+/*
+ * sdb_ast_const_t represents a constant value.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       sdb_data_t value;
+} sdb_ast_const_t;
+#define SDB_AST_CONST(obj) ((sdb_ast_const_t *)(obj))
+
+/*
+ * sdb_ast_value_t represents an object-specific value: sibling nodes,
+ * attributes, or field values.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int type; /* attribute or field */
+       char *name; /* object name; optional */
+} sdb_ast_value_t;
+#define SDB_AST_VALUE(obj) ((sdb_ast_value_t *)(obj))
+
+/*
+ * sdb_ast_fetch_t represents a FETCH command.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int obj_type;
+       char *hostname; /* optional */
+       char *name;
+       sdb_ast_node_t *filter; /* optional */
+} sdb_ast_fetch_t;
+#define SDB_AST_FETCH(obj) ((sdb_ast_fetch_t *)(obj))
+
+/*
+ * sdb_ast_list_t represents a LIST command.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int obj_type;
+       sdb_ast_node_t *filter; /* optional */
+} sdb_ast_list_t;
+#define SDB_AST_LIST(obj) ((sdb_ast_list_t *)(obj))
+
+/*
+ * sdb_ast_lookup_t represents a LOOKUP command.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int obj_type;
+       sdb_ast_node_t *matcher; /* optional */
+       sdb_ast_node_t *filter; /* optional */
+} sdb_ast_lookup_t;
+#define SDB_AST_LOOKUP(obj) ((sdb_ast_lookup_t *)(obj))
+
+/*
+ * sdb_ast_store_t represents a STORE command.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       int obj_type;
+       char *hostname;  /* optional */
+       int parent_type; /* optional */
+       char *parent;    /* optional */
+       char *name;
+       sdb_time_t last_update;
+
+       /* metric specific */
+       char *store_type;
+       char *store_id;
+
+       /* attribute specific */
+       sdb_data_t value;
+} sdb_ast_store_t;
+#define SDB_AST_STORE(obj) ((sdb_ast_store_t *)(obj))
+
+/*
+ * sdb_ast_timeseries_t represents a TIMESERIES command.
+ */
+typedef struct {
+       sdb_ast_node_t super;
+       char *hostname;
+       char *metric;
+       sdb_time_t start;
+       sdb_time_t end;
+} sdb_ast_timeseries_t;
+#define SDB_AST_TIMESERIES(obj) ((sdb_ast_timeseries_t *)(obj))
+
+/*
+ * AST constructors:
+ * Newly created nodes take ownership of any dynamically allocated objects
+ * (node objects, dynamically allocated constant values, strings). The memory
+ * will be freed when destroying the node using sdb_object_deref.
+ *
+ * The constructors do not verify any arguments. The analyzer has to be used
+ * for that purpose.
+ */
+
+/*
+ * sdb_ast_op_create:
+ * Creates an AST node representing a simple (ary or unary) operation. The
+ * newly created node takes ownership of the left and right nodes.
+ */
+sdb_ast_node_t *
+sdb_ast_op_create(int kind, sdb_ast_node_t *left, sdb_ast_node_t *right);
+
+/*
+ * sdb_ast_iter_create:
+ * Creates an AST node representing an iterator. The newly created node takes
+ * ownership of the iter and expr nodes.
+ */
+sdb_ast_node_t *
+sdb_ast_iter_create(int kind, int op,
+               sdb_ast_node_t *iter, sdb_ast_node_t *expr);
+
+/*
+ * sdb_ast_typed_create:
+ * Creates an AST node representing a typed expression. Thew newly created
+ * node takes ownership of the expr node.
+ */
+sdb_ast_node_t *
+sdb_ast_typed_create(int type, sdb_ast_node_t *expr);
+
+/*
+ * sdb_ast_const_create:
+ * Creates an AST node representing a constant value. The newly created node
+ * takes ownership of the value object.
+ */
+sdb_ast_node_t *
+sdb_ast_const_create(sdb_data_t value);
+
+/*
+ * sdb_ast_value_create:
+ * Creates an AST node representing an object-specific value (sibling nodes,
+ * attributes, or field values). The newly created node takes ownership of the
+ * string value.
+ */
+sdb_ast_node_t *
+sdb_ast_value_create(int type, char *name);
+
+/*
+ * sdb_ast_fetch_create:
+ * Creates an AST node representing a FETCH command. The newly created node
+ * takes ownership of the strings and the filter node.
+ */
+sdb_ast_node_t *
+sdb_ast_fetch_create(int obj_type, char *hostname, char *name,
+               sdb_ast_node_t *filter);
+
+/*
+ * sdb_ast_list_create:
+ * Creates an AST node representing a LIST command. The newly created node
+ * takes ownership of the filter node.
+ */
+sdb_ast_node_t *
+sdb_ast_list_create(int obj_type, sdb_ast_node_t *filter);
+
+/*
+ * sdb_ast_lookup_create:
+ * Creates an AST node representing a LOOKUP command. The newly created node
+ * takes ownership of the matcher and filter nodes.
+ */
+sdb_ast_node_t *
+sdb_ast_lookup_create(int obj_type, sdb_ast_node_t *matcher,
+               sdb_ast_node_t *filter);
+
+/*
+ * sdb_ast_store_create:
+ * Creates an AST node representing a STORE command. Thew newly created node
+ * takes ownership of all strings and the value object.
+ */
+sdb_ast_node_t *
+sdb_ast_store_create(int obj_type, char *hostname,
+               int parent_type, char *parent, char *name, sdb_time_t last_update,
+               char *store_type, char *store_id, sdb_data_t value);
+
+/*
+ * sdb_ast_timeseries_create:
+ * Creates an AST node representing a TIMESERIES command. The newly created
+ * node takes ownership of the strings.
+ */
+sdb_ast_node_t *
+sdb_ast_timeseries_create(char *hostname, char *metric,
+               sdb_time_t start, sdb_time_t end);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ! SDB_PARSER_AST_H */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
diff --git a/src/parser/ast.c b/src/parser/ast.c
new file mode 100644 (file)
index 0000000..a64178b
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * SysDB - src/parser/ast.c
+ * Copyright (C) 2013-2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/store.h"
+
+#include "parser/ast.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * data types
+ */
+
+static void
+op_destroy(sdb_object_t *obj)
+{
+       sdb_ast_op_t *op = SDB_AST_OP(obj);
+       sdb_object_deref(SDB_OBJ(op->left));
+       sdb_object_deref(SDB_OBJ(op->right));
+       op->left = op->right = NULL;
+} /* op_destroy */
+
+static void
+iter_destroy(sdb_object_t *obj)
+{
+       sdb_ast_iter_t *iter = SDB_AST_ITER(obj);
+       sdb_object_deref(SDB_OBJ(iter->iter));
+       sdb_object_deref(SDB_OBJ(iter->expr));
+       iter->iter = iter->expr = NULL;
+} /* iter_destroy */
+
+static void
+typed_destroy(sdb_object_t *obj)
+{
+       sdb_ast_typed_t *typed = SDB_AST_TYPED(obj);
+       sdb_object_deref(SDB_OBJ(typed->expr));
+       typed->expr = NULL;
+} /* typed_destroy */
+
+static void
+const_destroy(sdb_object_t *obj)
+{
+       sdb_ast_const_t *c = SDB_AST_CONST(obj);
+       sdb_data_free_datum(&c->value);
+} /* const_destroy */
+
+static void
+value_destroy(sdb_object_t *obj)
+{
+       sdb_ast_value_t *value = SDB_AST_VALUE(obj);
+       if (value->name)
+               free(value->name);
+       value->name = NULL;
+} /* value_destroy */
+
+static void
+fetch_destroy(sdb_object_t *obj)
+{
+       sdb_ast_fetch_t *fetch = SDB_AST_FETCH(obj);
+       if (fetch->hostname)
+               free(fetch->hostname);
+       if (fetch->name)
+               free(fetch->name);
+       fetch->hostname = fetch->name = NULL;
+
+       sdb_object_deref(SDB_OBJ(fetch->filter));
+       fetch->filter = NULL;
+} /* fetch_destroy */
+
+static void
+list_destroy(sdb_object_t *obj)
+{
+       sdb_ast_list_t *list = SDB_AST_LIST(obj);
+       sdb_object_deref(SDB_OBJ(list->filter));
+       list->filter = NULL;
+} /* list_destroy */
+
+static void
+lookup_destroy(sdb_object_t *obj)
+{
+       sdb_ast_lookup_t *lookup = SDB_AST_LOOKUP(obj);
+       sdb_object_deref(SDB_OBJ(lookup->matcher));
+       sdb_object_deref(SDB_OBJ(lookup->filter));
+       lookup->matcher = lookup->filter = NULL;
+} /* lookup_destroy */
+
+static void
+store_destroy(sdb_object_t *obj)
+{
+       sdb_ast_store_t *store = SDB_AST_STORE(obj);
+       if (store->hostname)
+               free(store->hostname);
+       if (store->parent)
+               free(store->parent);
+       if (store->name)
+               free(store->name);
+       store->hostname = store->parent = store->name = NULL;
+
+       if (store->store_type)
+               free(store->store_type);
+       if (store->store_id)
+               free(store->store_id);
+       store->store_type = store->store_id = NULL;
+
+       sdb_data_free_datum(&store->value);
+} /* store_destroy */
+
+static void
+timeseries_destroy(sdb_object_t *obj)
+{
+       sdb_ast_timeseries_t *timeseries = SDB_AST_TIMESERIES(obj);
+       if (timeseries->hostname)
+               free(timeseries->hostname);
+       if (timeseries->metric)
+               free(timeseries->metric);
+       timeseries->hostname = timeseries->metric = NULL;
+} /* timeseries_destroy */
+
+static sdb_type_t op_type = {
+       /* size */ sizeof(sdb_ast_op_t),
+       /* init */ NULL,
+       /* destroy */ op_destroy,
+};
+
+static sdb_type_t iter_type = {
+       /* size */ sizeof(sdb_ast_iter_t),
+       /* init */ NULL,
+       /* destroy */ iter_destroy,
+};
+
+static sdb_type_t typed_type = {
+       /* size */ sizeof(sdb_ast_typed_t),
+       /* init */ NULL,
+       /* destroy */ typed_destroy,
+};
+
+static sdb_type_t const_type = {
+       /* size */ sizeof(sdb_ast_const_t),
+       /* init */ NULL,
+       /* destroy */ const_destroy,
+};
+
+static sdb_type_t value_type = {
+       /* size */ sizeof(sdb_ast_value_t),
+       /* init */ NULL,
+       /* destroy */ value_destroy,
+};
+
+static sdb_type_t fetch_type = {
+       /* size */ sizeof(sdb_ast_fetch_t),
+       /* init */ NULL,
+       /* destroy */ fetch_destroy,
+};
+
+static sdb_type_t list_type = {
+       /* size */ sizeof(sdb_ast_list_t),
+       /* init */ NULL,
+       /* destroy */ list_destroy,
+};
+
+static sdb_type_t lookup_type = {
+       /* size */ sizeof(sdb_ast_lookup_t),
+       /* init */ NULL,
+       /* destroy */ lookup_destroy,
+};
+
+static sdb_type_t st_type = {
+       /* size */ sizeof(sdb_ast_store_t),
+       /* init */ NULL,
+       /* destroy */ store_destroy,
+};
+
+static sdb_type_t ts_type = {
+       /* size */ sizeof(sdb_ast_timeseries_t),
+       /* init */ NULL,
+       /* destroy */ timeseries_destroy,
+};
+
+/*
+ * public API
+ */
+
+sdb_ast_node_t *
+sdb_ast_op_create(int kind, sdb_ast_node_t *left, sdb_ast_node_t *right)
+{
+       sdb_ast_op_t *op;
+       op = SDB_AST_OP(sdb_object_create(SDB_AST_OP_TO_STRING(kind), op_type));
+       if (! op)
+               return NULL;
+
+       op->super.type = SDB_AST_TYPE_OPERATOR;
+
+       op->kind = kind;
+       op->left = left;
+       op->right = right;
+       return SDB_AST_NODE(op);
+} /* sdb_ast_op_create */
+
+sdb_ast_node_t *
+sdb_ast_iter_create(int kind, int op,
+               sdb_ast_node_t *iter, sdb_ast_node_t *expr)
+{
+       sdb_ast_iter_t *i;
+       i = SDB_AST_ITER(sdb_object_create(SDB_AST_OP_TO_STRING(kind), iter_type));
+       if (! i)
+               return NULL;
+
+       i->super.type = SDB_AST_TYPE_ITERATOR;
+
+       i->kind = kind;
+       i->op = op;
+       i->iter = iter;
+       i->expr = expr;
+       return SDB_AST_NODE(i);
+} /* sdb_ast_iter_create */
+
+sdb_ast_node_t *
+sdb_ast_typed_create(int type, sdb_ast_node_t *expr)
+{
+       char name[32];
+       sdb_ast_typed_t *typed;
+       size_t i;
+
+       strncpy(name, SDB_STORE_TYPE_TO_NAME(type), sizeof(name));
+       for (i = 0; i < strlen(name); ++i)
+               name[i] = (char)toupper((int)name[i]);
+       typed = SDB_AST_TYPED(sdb_object_create(name, typed_type));
+       if (! typed)
+               return NULL;
+
+       typed->super.type = SDB_AST_TYPE_TYPED;
+
+       typed->type = type;
+       typed->expr = expr;
+       return SDB_AST_NODE(typed);
+} /* sdb_ast_typed_create */
+
+sdb_ast_node_t *
+sdb_ast_const_create(sdb_data_t value)
+{
+       sdb_ast_const_t *c;
+       c = SDB_AST_CONST(sdb_object_create("CONST", const_type));
+       if (! c)
+               return NULL;
+
+       c->super.type = SDB_AST_TYPE_CONST;
+
+       c->value = value;
+       return SDB_AST_NODE(c);
+} /* sdb_ast_const_create */
+
+sdb_ast_node_t *
+sdb_ast_value_create(int type, char *name)
+{
+       sdb_ast_value_t *value;
+       value = SDB_AST_VALUE(sdb_object_create("VALUE", value_type));
+       if (! value)
+               return NULL;
+
+       value->super.type = SDB_AST_TYPE_VALUE;
+
+       value->type = type;
+       value->name = name;
+       return SDB_AST_NODE(value);
+} /* sdb_ast_value_create */
+
+sdb_ast_node_t *
+sdb_ast_fetch_create(int obj_type, char *hostname, char *name,
+               sdb_ast_node_t *filter)
+{
+       sdb_ast_fetch_t *fetch;
+       fetch = SDB_AST_FETCH(sdb_object_create("FETCH", fetch_type));
+       if (! fetch)
+               return NULL;
+
+       fetch->super.type = SDB_AST_TYPE_FETCH;
+
+       fetch->obj_type = obj_type;
+       fetch->hostname = hostname;
+       fetch->name = name;
+       fetch->filter = filter;
+       return SDB_AST_NODE(fetch);
+} /* sdb_ast_fetch_create */
+
+sdb_ast_node_t *
+sdb_ast_list_create(int obj_type, sdb_ast_node_t *filter)
+{
+       sdb_ast_list_t *list;
+       list = SDB_AST_LIST(sdb_object_create("LIST", list_type));
+       if (! list)
+               return NULL;
+
+       list->super.type = SDB_AST_TYPE_LIST;
+
+       list->obj_type = obj_type;
+       list->filter = filter;
+       return SDB_AST_NODE(list);
+} /* sdb_ast_list_create */
+
+sdb_ast_node_t *
+sdb_ast_lookup_create(int obj_type, sdb_ast_node_t *matcher,
+               sdb_ast_node_t *filter)
+{
+       sdb_ast_lookup_t *lookup;
+       lookup = SDB_AST_LOOKUP(sdb_object_create("LOOKUP", lookup_type));
+       if (! lookup)
+               return NULL;
+
+       lookup->super.type = SDB_AST_TYPE_LOOKUP;
+
+       lookup->obj_type = obj_type;
+       lookup->matcher = matcher;
+       lookup->filter = filter;
+       return SDB_AST_NODE(lookup);
+} /* sdb_ast_lookup_create */
+
+sdb_ast_node_t *
+sdb_ast_store_create(int obj_type, char *hostname,
+               int parent_type, char *parent, char *name, sdb_time_t last_update,
+               char *store_type, char *store_id, sdb_data_t value)
+{
+       sdb_ast_store_t *store;
+       store = SDB_AST_STORE(sdb_object_create("STORE", st_type));
+       if (! store)
+               return NULL;
+
+       store->super.type = SDB_AST_TYPE_STORE;
+
+       store->obj_type = obj_type;
+       store->hostname = hostname;
+       store->parent_type = parent_type;
+       store->parent = parent;
+       store->name = name;
+       store->last_update = last_update;
+       store->store_type = store_type;
+       store->store_id = store_id;
+       store->value = value;
+       return SDB_AST_NODE(store);
+} /* sdb_ast_store_create */
+
+sdb_ast_node_t *
+sdb_ast_timeseries_create(char *hostname, char *metric,
+               sdb_time_t start, sdb_time_t end)
+{
+       sdb_ast_timeseries_t *timeseries;
+       timeseries = SDB_AST_TIMESERIES(sdb_object_create("TIMESERIES", ts_type));
+       if (! timeseries)
+               return NULL;
+
+       timeseries->super.type = SDB_AST_TYPE_TIMESERIES;
+
+       timeseries->hostname = hostname;
+       timeseries->metric = metric;
+       timeseries->start = start;
+       timeseries->end = end;
+       return SDB_AST_NODE(timeseries);
+} /* sdb_ast_timeseries_create */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */