ecae40f890c2842d82f92d701ab0a8e3137025f9
1 /*
2 * SysDB - src/parser/analyzer.c
3 * Copyright (C) 2014-2015 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 #include "sysdb.h"
30 #include "parser/ast.h"
31 #include "parser/parser.h"
32 #include "utils/error.h"
33 #include "utils/strbuf.h"
35 #include <assert.h>
36 #include <stdarg.h>
37 #include <stdbool.h>
38 #include <string.h>
40 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
42 typedef struct {
43 int type;
44 bool iter;
45 } context_t;
47 #define FILTER_CONTEXT -1
48 static const context_t FILTER_CTX = { FILTER_CONTEXT, 0 };
50 static int
51 analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
53 /*
54 * error reporting
55 */
57 static void
58 op_error(sdb_strbuf_t *errbuf, sdb_ast_op_t *op, const char *reason)
59 {
60 sdb_strbuf_sprintf(errbuf, "Invalid operation %s %s %s (%s)",
61 SDB_TYPE_TO_STRING(op->left->data_type),
62 SDB_AST_OP_TO_STRING(op->kind),
63 SDB_TYPE_TO_STRING(op->right->data_type),
64 reason);
65 } /* op_error */
67 static void
68 __attribute__((format(printf, 3, 4)))
69 iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...)
70 {
71 char r[1024];
72 va_list ap;
74 va_start(ap, reason);
75 vsnprintf(r, sizeof(r), reason, ap);
76 va_end(ap);
78 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
79 && (! SDB_AST_OP(iter->expr)->left));
80 sdb_strbuf_sprintf(errbuf, "Invalid iterator %s %s %s %s (%s)",
81 SDB_AST_OP_TO_STRING(iter->kind),
82 SDB_TYPE_TO_STRING(iter->iter->data_type),
83 SDB_AST_OP_TO_STRING(SDB_AST_OP(iter->expr)->kind),
84 SDB_TYPE_TO_STRING(SDB_AST_OP(iter->expr)->right->data_type),
85 r);
86 } /* iter_error */
88 /*
89 * expression nodes
90 */
92 static int
93 analyze_logical(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
94 {
95 if (ctx.iter) {
96 op_error(errbuf, op, "cannot evaluate in iterator context");
97 return -1;
98 }
100 switch (op->kind) {
101 case SDB_AST_OR:
102 case SDB_AST_AND:
103 if (! SDB_AST_IS_LOGICAL(op->left)) {
104 sdb_strbuf_sprintf(errbuf, "Invalid left operand (%s) "
105 "in %s expression", SDB_AST_TYPE_TO_STRING(op->left),
106 SDB_AST_OP_TO_STRING(op->kind));
107 return -1;
108 }
109 if (analyze_node(ctx, op->left, errbuf))
110 return -1;
111 /* fallthrough */
112 case SDB_AST_NOT:
113 if (! SDB_AST_IS_LOGICAL(op->right)) {
114 sdb_strbuf_sprintf(errbuf, "Invalid right operand (%s) "
115 "in %s expression", SDB_AST_TYPE_TO_STRING(op->right),
116 SDB_AST_OP_TO_STRING(op->kind));
117 return -1;
118 }
119 if (analyze_node(ctx, op->right, errbuf))
120 return -1;
121 break;
123 case SDB_AST_LT:
124 case SDB_AST_LE:
125 case SDB_AST_EQ:
126 case SDB_AST_NE:
127 case SDB_AST_GE:
128 case SDB_AST_GT:
129 {
130 if (analyze_node(ctx, op->left, errbuf))
131 return -1;
132 if (analyze_node(ctx, op->right, errbuf))
133 return -1;
135 if ((op->left->data_type > 0) && (op->right->data_type > 0)) {
136 if (op->left->data_type == op->right->data_type)
137 return 0;
138 op_error(errbuf, op, "type mismatch");
139 return -1;
140 }
141 if ((op->left->data_type > 0) && (op->left->data_type & SDB_TYPE_ARRAY)) {
142 op_error(errbuf, op, "array not allowed");
143 return -1;
144 }
145 if ((op->right->data_type > 0) && (op->right->data_type & SDB_TYPE_ARRAY)) {
146 op_error(errbuf, op, "array not allowed");
147 return -1;
148 }
149 break;
150 }
152 case SDB_AST_REGEX:
153 case SDB_AST_NREGEX:
154 if (analyze_node(ctx, op->left, errbuf))
155 return -1;
156 if (analyze_node(ctx, op->right, errbuf))
157 return -1;
159 /* all types are supported for the left operand
160 * TODO: introduce a cast operator if it's not a string */
161 if ((op->right->data_type > 0)
162 && (op->right->data_type != SDB_TYPE_REGEX)
163 && (op->right->data_type != SDB_TYPE_STRING)) {
164 op_error(errbuf, op, "invalid regex");
165 return -1;
166 }
167 break;
169 case SDB_AST_ISNULL:
170 case SDB_AST_ISTRUE:
171 case SDB_AST_ISFALSE:
172 if (analyze_node(ctx, op->right, errbuf))
173 return -1;
174 break;
176 case SDB_AST_IN:
177 if (analyze_node(ctx, op->left, errbuf))
178 return -1;
179 if (analyze_node(ctx, op->right, errbuf))
180 return -1;
182 if ((op->right->data_type > 0) && (! (op->right->data_type & SDB_TYPE_ARRAY))) {
183 op_error(errbuf, op, "array expected");
184 return -1;
185 }
186 /* the left operand may be a scalar or an array but the element
187 * type has to match */
188 if ((op->left->data_type > 0) && (op->right->data_type > 0)
189 && ((op->left->data_type & 0xff) != (op->right->data_type & 0xff))) {
190 op_error(errbuf, op, "type mismatch");
191 return -1;
192 }
193 break;
195 default:
196 sdb_strbuf_sprintf(errbuf, "Unknown operand type %d", op->kind);
197 return -1;
198 }
199 return 0;
200 } /* analyze_logical */
202 static int
203 analyze_arith(context_t ctx, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
204 {
205 if (analyze_node(ctx, op->left, errbuf))
206 return -1;
207 if (analyze_node(ctx, op->right, errbuf))
208 return -1;
209 SDB_AST_NODE(op)->data_type = sdb_data_expr_type(SDB_AST_OP_TO_DATA_OP(op->kind),
210 op->left->data_type, op->right->data_type);
212 if ((op->left->data_type > 0) && (op->right->data_type > 0)
213 && (SDB_AST_NODE(op)->data_type <= 0)) {
214 op_error(errbuf, op, "type mismatch");
215 return -1;
216 }
218 /* TODO: replace constant arithmetic operations with a constant value */
219 return 0;
220 } /* analyze_arith */
222 static int
223 analyze_iter(context_t ctx, sdb_ast_iter_t *iter, sdb_strbuf_t *errbuf)
224 {
225 sdb_ast_const_t c = SDB_AST_CONST_INIT;
226 context_t iter_ctx = ctx;
227 int status;
229 if (ctx.iter) {
230 iter_error(errbuf, iter, "nested iterators are not supported");
231 return -1;
232 }
234 iter_ctx.iter = 1;
235 if (analyze_node(iter_ctx, iter->iter, errbuf))
236 return -1;
238 if (iter->iter->data_type > 0) {
239 if (! (iter->iter->data_type & SDB_TYPE_ARRAY)) {
240 iter_error(errbuf, iter, "cannot iterate values of type %s",
241 SDB_TYPE_TO_STRING(iter->iter->data_type));
242 return -1;
243 }
244 c.value.type = iter->iter->data_type & 0xff;
245 }
247 /* TODO: support other setups as well */
248 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
249 && (! SDB_AST_OP(iter->expr)->left));
251 SDB_AST_OP(iter->expr)->left = SDB_AST_NODE(&c);
252 status = analyze_node(ctx, iter->expr, errbuf);
253 SDB_AST_OP(iter->expr)->left = NULL;
254 if (status)
255 return -1;
256 return 0;
257 } /* analyze_iter */
259 static int
260 analyze_const(context_t __attribute__((unused)) ctx, sdb_ast_const_t *c,
261 sdb_strbuf_t __attribute__((unused)) *errbuf)
262 {
263 SDB_AST_NODE(c)->data_type = c->value.type;
264 return 0;
265 } /* analyze_const */
267 static int
268 analyze_value(context_t ctx, sdb_ast_value_t *v, sdb_strbuf_t *errbuf)
269 {
270 if (v->type != SDB_ATTRIBUTE)
271 SDB_AST_NODE(v)->data_type = SDB_FIELD_TYPE(v->type);
273 if ((v->type != SDB_ATTRIBUTE) && v->name) {
274 sdb_strbuf_sprintf(errbuf, "Invalid expression %s[%s]",
275 SDB_FIELD_TO_NAME(v->type), v->name);
276 return -1;
277 }
278 else if ((v->type == SDB_ATTRIBUTE) && (! v->name)) {
279 sdb_strbuf_sprintf(errbuf, "Invalid expression attribute[] "
280 "(missing name)");
281 return -1;
282 }
284 /* this would be caught by the type check in analyze_iter but we're able
285 * to provide a more specific error message here */
286 if (ctx.iter && (v->type != SDB_FIELD_BACKEND)) {
287 /* only backend values are iterable */
288 char value_str[64 + (v->name ? strlen(v->name) : 0)];
289 if (v->type == SDB_ATTRIBUTE)
290 snprintf(value_str, sizeof(value_str), "attribute[%s]", v->name);
291 else
292 snprintf(value_str, sizeof(value_str), "'%s'", SDB_FIELD_TO_NAME(v->type));
293 sdb_strbuf_sprintf(errbuf, "Cannot iterate %s (scalar value)", value_str);
294 return -1;
295 }
297 if ((ctx.type != SDB_ATTRIBUTE) && (v->type == SDB_FIELD_VALUE)) {
298 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.value",
299 SDB_FIELD_TO_NAME(ctx.type));
300 return -1;
301 }
302 if ((ctx.type != SDB_METRIC) && (v->type == SDB_FIELD_TIMESERIES)) {
303 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.timeseries",
304 SDB_FIELD_TO_NAME(ctx.type));
305 return -1;
306 }
307 return 0;
308 } /* analyze_value */
310 static int
311 analyze_typed(context_t ctx, sdb_ast_typed_t *t, sdb_strbuf_t *errbuf)
312 {
313 context_t child_ctx = ctx;
314 bool needs_iter = 0;
315 bool valid = 1;
317 if ((t->expr->type != SDB_AST_TYPE_VALUE)
318 && (t->expr->type != SDB_AST_TYPE_TYPED)) {
319 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s",
320 SDB_STORE_TYPE_TO_NAME(t->type),
321 SDB_AST_TYPE_TO_STRING(t->expr));
322 return -1;
323 }
324 if ((t->type != SDB_ATTRIBUTE) && (! VALID_OBJ_TYPE(t->type))) {
325 sdb_strbuf_sprintf(errbuf, "Invalid expression %#x.%s",
326 t->type, SDB_AST_TYPE_TO_STRING(t->expr));
327 return -1;
328 }
330 if (ctx.type > 0) {
331 if ((ctx.type == t->type)
332 || ((t->type == SDB_HOST) && (ctx.type != SDB_ATTRIBUTE))) {
333 /* self-references and references to the parent host are always fine */
334 }
335 else if (t->type == SDB_ATTRIBUTE) {
336 /* references to attributes are always fine */
337 needs_iter = 1;
338 }
339 else if ((ctx.type == SDB_HOST)
340 && ((t->type == SDB_SERVICE) || (t->type == SDB_METRIC))) {
341 /* only hosts may reference services and metrics */
342 needs_iter = 1;
343 }
344 else {
345 valid = 0;
346 }
347 }
348 else if (ctx.type == FILTER_CONTEXT) {
349 if (t->type == SDB_ATTRIBUTE) {
350 /* all objects have attributes */
351 needs_iter = 1;
352 }
353 else if ((t->type == SDB_SERVICE) || (t->type == SDB_METRIC)) {
354 /* these will be iterators for *some* operations;
355 * better forbid this altogether */
356 valid = 0;
357 }
358 }
360 if (needs_iter) {
361 if (! ctx.iter)
362 valid = 0;
363 else
364 child_ctx.iter = 0;
365 } /* else: push ctx.iter down to the child node */
367 if (! valid) {
368 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s in %s context",
369 SDB_STORE_TYPE_TO_NAME(t->type),
370 SDB_AST_TYPE_TO_STRING(t->expr),
371 SDB_STORE_TYPE_TO_NAME(ctx.type));
372 return -1;
373 }
375 child_ctx.type = t->type;
376 if (analyze_node(child_ctx, t->expr, errbuf))
377 return -1;
378 SDB_AST_NODE(t)->data_type = t->expr->data_type;
380 if (needs_iter && (SDB_AST_NODE(t)->data_type > 0)) {
381 if (SDB_AST_NODE(t)->data_type & SDB_TYPE_ARRAY) {
382 sdb_strbuf_sprintf(errbuf, "Cannot access array inside iterator");
383 return -1;
384 }
385 /* Tell the caller that we're accessing an iterator. */
386 SDB_AST_NODE(t)->data_type |= SDB_TYPE_ARRAY;
387 }
388 return 0;
389 } /* analyze_typed */
391 static int
392 analyze_node(context_t ctx, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
393 {
394 if (! node) {
395 sdb_strbuf_sprintf(errbuf, "Empty AST node");
396 return -1;
397 }
399 /* unknown by default */
400 node->data_type = -1;
402 if ((node->type == SDB_AST_TYPE_OPERATOR)
403 && (SDB_AST_IS_LOGICAL(node)))
404 return analyze_logical(ctx, SDB_AST_OP(node), errbuf);
405 else if ((node->type == SDB_AST_TYPE_OPERATOR)
406 && (SDB_AST_IS_ARITHMETIC(node)))
407 return analyze_arith(ctx, SDB_AST_OP(node), errbuf);
408 else if (node->type == SDB_AST_TYPE_ITERATOR)
409 return analyze_iter(ctx, SDB_AST_ITER(node), errbuf);
410 else if (node->type == SDB_AST_TYPE_CONST)
411 return analyze_const(ctx, SDB_AST_CONST(node), errbuf);
412 else if (node->type == SDB_AST_TYPE_VALUE)
413 return analyze_value(ctx, SDB_AST_VALUE(node), errbuf);
414 else if (node->type == SDB_AST_TYPE_TYPED)
415 return analyze_typed(ctx, SDB_AST_TYPED(node), errbuf);
417 sdb_strbuf_sprintf(errbuf, "Invalid expression node "
418 "of type %#x", node->type);
419 return -1;
420 } /* analyze_node */
422 /*
423 * top level / command nodes
424 */
426 static int
427 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
428 {
429 if (! VALID_OBJ_TYPE(fetch->obj_type)) {
430 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
431 "in FETCH command", fetch->obj_type);
432 return -1;
433 }
434 if (! fetch->name) {
435 sdb_strbuf_sprintf(errbuf, "Missing object name in "
436 "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
437 return -1;
438 }
440 if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
441 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
442 "in FETCH HOST command", fetch->hostname);
443 return -1;
444 }
445 else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
446 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
447 "in FETCH %s command", fetch->name,
448 SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
449 return -1;
450 }
452 if (fetch->filter)
453 return analyze_node(FILTER_CTX, fetch->filter, errbuf);
454 return 0;
455 } /* analyze_fetch */
457 static int
458 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
459 {
460 if (! VALID_OBJ_TYPE(list->obj_type)) {
461 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
462 "in LIST command", list->obj_type);
463 return -1;
464 }
465 if (list->filter)
466 return analyze_node(FILTER_CTX, list->filter, errbuf);
467 return 0;
468 } /* analyze_list */
470 static int
471 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
472 {
473 if (! VALID_OBJ_TYPE(lookup->obj_type)) {
474 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
475 "in LOOKUP command", lookup->obj_type);
476 return -1;
477 }
478 if (lookup->matcher) {
479 context_t ctx = { lookup->obj_type, 0 };
480 if (analyze_node(ctx, lookup->matcher, errbuf))
481 return -1;
482 }
483 if (lookup->filter)
484 return analyze_node(FILTER_CTX, lookup->filter, errbuf);
485 return 0;
486 } /* analyze_lookup */
488 static int
489 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
490 {
491 if ((st->obj_type != SDB_ATTRIBUTE)
492 && (! VALID_OBJ_TYPE(st->obj_type))) {
493 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
494 "in STORE command", st->obj_type);
495 return -1;
496 }
497 if (! st->name) {
498 sdb_strbuf_sprintf(errbuf, "Missing object name in "
499 "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
500 return -1;
501 }
503 if ((st->obj_type == SDB_HOST) && st->hostname) {
504 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
505 "in STORE HOST command", st->hostname);
506 return -1;
507 }
508 else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
509 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
510 "in STORE %s command", st->name,
511 SDB_STORE_TYPE_TO_NAME(st->obj_type));
512 return -1;
513 }
515 if (st->obj_type == SDB_ATTRIBUTE) {
516 if ((st->parent_type <= 0) && st->parent) {
517 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
518 "in STORE %s command", st->parent,
519 SDB_STORE_TYPE_TO_NAME(st->obj_type));
520 return -1;
521 }
522 else if (st->parent_type > 0) {
523 if (! VALID_OBJ_TYPE(st->parent_type)) {
524 sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
525 "in STORE %s command", st->parent_type,
526 SDB_STORE_TYPE_TO_NAME(st->obj_type));
527 return -1;
528 }
529 if (! st->parent) {
530 sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
531 "in STORE %s command",
532 SDB_STORE_TYPE_TO_NAME(st->parent_type),
533 SDB_STORE_TYPE_TO_NAME(st->obj_type));
534 return -1;
535 }
536 }
537 }
538 else if ((st->parent_type > 0) || st->parent) {
539 sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
540 "in STORE %s command",
541 SDB_STORE_TYPE_TO_NAME(st->parent_type),
542 st->parent ? st->parent : "<unknown>",
543 SDB_STORE_TYPE_TO_NAME(st->obj_type));
544 return -1;
545 }
547 if (st->obj_type == SDB_METRIC) {
548 if ((! st->store_type) != (! st->store_id)) {
549 sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
550 "in STORE METRIC command",
551 st->store_type ? st->store_type : "<unknown>",
552 st->store_id ? st->store_id : "<unknown>");
553 return -1;
554 }
555 }
556 else if (st->store_type || st->store_id) {
557 sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
558 "in STORE %s command",
559 st->store_type ? st->store_type : "<unknown>",
560 st->store_id ? st->store_id : "<unknown>",
561 SDB_STORE_TYPE_TO_NAME(st->obj_type));
562 return -1;
563 }
565 if ((! (st->obj_type == SDB_ATTRIBUTE))
566 && (st->value.type != SDB_TYPE_NULL)) {
567 char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
568 sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
569 sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
570 v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
571 return -1;
572 }
573 return 0;
574 } /* analyze_store */
576 static int
577 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
578 {
579 if (! ts->hostname) {
580 sdb_strbuf_sprintf(errbuf, "Missing hostname in TIMESERIES command");
581 return -1;
582 }
583 if (! ts->metric) {
584 sdb_strbuf_sprintf(errbuf, "Missing metric name in TIMESERIES command");
585 return -1;
586 }
587 if (ts->end <= ts->start) {
588 char start_str[64], end_str[64];
589 sdb_strftime(start_str, sizeof(start_str), ts->start);
590 sdb_strftime(end_str, sizeof(end_str), ts->end);
591 sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
592 "end time (%s) in TIMESERIES command", start_str, end_str);
593 return -1;
594 }
595 return 0;
596 } /* analyze_timeseries */
598 /*
599 * public API
600 */
602 int
603 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
604 {
605 if (! node) {
606 sdb_strbuf_sprintf(errbuf, "Empty AST node");
607 return -1;
608 }
610 /* top-level nodes don't have a type */
611 node->data_type = -1;
613 if (node->type == SDB_AST_TYPE_FETCH)
614 return analyze_fetch(SDB_AST_FETCH(node), errbuf);
615 else if (node->type == SDB_AST_TYPE_LIST)
616 return analyze_list(SDB_AST_LIST(node), errbuf);
617 else if (node->type == SDB_AST_TYPE_LOOKUP)
618 return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
619 else if (node->type == SDB_AST_TYPE_STORE)
620 return analyze_store(SDB_AST_STORE(node), errbuf);
621 else if (node->type == SDB_AST_TYPE_TIMESERIES)
622 return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
624 sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
625 "of type %#x", node->type);
626 return -1;
627 } /* sdb_parser_analyze */
629 int
630 sdb_parser_analyze_conditional(int context,
631 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
632 {
633 context_t ctx = { context, 0 };
634 if (! VALID_OBJ_TYPE(context)) {
635 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
636 return -1;
637 }
638 if (! node) {
639 sdb_strbuf_sprintf(errbuf, "Empty conditional node");
640 return -1;
641 }
642 if (! SDB_AST_IS_LOGICAL(node)) {
643 sdb_strbuf_sprintf(errbuf, "Not a conditional node (got %s)",
644 SDB_AST_TYPE_TO_STRING(node));
645 return -1;
646 }
647 return analyze_node(ctx, node, errbuf);
648 } /* sdb_parser_analyze_conditional */
650 int
651 sdb_parser_analyze_arith(int context,
652 sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
653 {
654 context_t ctx = { context, 0 };
655 if (! VALID_OBJ_TYPE(context)) {
656 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x", context);
657 return -1;
658 }
659 if (! node) {
660 sdb_strbuf_sprintf(errbuf, "Empty arithmetic node");
661 return -1;
662 }
663 if (! SDB_AST_IS_ARITHMETIC(node)) {
664 sdb_strbuf_sprintf(errbuf, "Not an arithmetic node (got %s)",
665 SDB_AST_TYPE_TO_STRING(node));
666 return -1;
667 }
668 return analyze_node(ctx, node, errbuf);
669 } /* sdb_parser_analyze_arith */
671 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */