28d312142ddca8a33b580d06b1503d4d2248de7d
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>
38 #define VALID_OBJ_TYPE(t) ((SDB_HOST <= (t)) && ((t) <= SDB_METRIC))
40 #define FILTER_CONTEXT -1
41 #define UNSPEC_CONTEXT -2
43 static int
44 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf);
46 /*
47 * error reporting
48 */
50 static void
51 op_error(sdb_strbuf_t *errbuf, sdb_ast_op_t *op, const char *reason)
52 {
53 sdb_strbuf_sprintf(errbuf, "Invalid operation %s %s %s (%s)",
54 SDB_TYPE_TO_STRING(op->left->data_type),
55 SDB_AST_OP_TO_STRING(op->kind),
56 SDB_TYPE_TO_STRING(op->right->data_type),
57 reason);
58 } /* op_error */
60 static void
61 __attribute__((format(printf, 3, 4)))
62 iter_error(sdb_strbuf_t *errbuf, sdb_ast_iter_t *iter, const char *reason, ...)
63 {
64 char r[1024];
65 va_list ap;
67 va_start(ap, reason);
68 vsnprintf(r, sizeof(r), reason, ap);
69 va_end(ap);
71 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
72 && (! SDB_AST_OP(iter->expr)->left));
73 sdb_strbuf_sprintf(errbuf, "Invalid iterator %s %s %s %s (%s)",
74 SDB_AST_OP_TO_STRING(iter->kind),
75 SDB_TYPE_TO_STRING(iter->iter->data_type),
76 SDB_AST_OP_TO_STRING(SDB_AST_OP(iter->expr)->kind),
77 SDB_TYPE_TO_STRING(SDB_AST_OP(iter->expr)->right->data_type),
78 r);
79 } /* iter_error */
81 /*
82 * expression nodes
83 */
85 static int
86 analyze_logical(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
87 {
88 switch (op->kind) {
89 case SDB_AST_OR:
90 case SDB_AST_AND:
91 if (! SDB_AST_IS_LOGICAL(op->left)) {
92 sdb_strbuf_sprintf(errbuf, "Invalid left operand (%s) "
93 "in %s expression", SDB_AST_TYPE_TO_STRING(op->left),
94 SDB_AST_OP_TO_STRING(op->kind));
95 return -1;
96 }
97 if (analyze_node(context, op->left, errbuf))
98 return -1;
99 /* fallthrough */
100 case SDB_AST_NOT:
101 if (! SDB_AST_IS_LOGICAL(op->right)) {
102 sdb_strbuf_sprintf(errbuf, "Invalid right operand (%s) "
103 "in %s expression", SDB_AST_TYPE_TO_STRING(op->right),
104 SDB_AST_OP_TO_STRING(op->kind));
105 return -1;
106 }
107 if (analyze_node(context, op->right, errbuf))
108 return -1;
109 break;
111 case SDB_AST_LT:
112 case SDB_AST_LE:
113 case SDB_AST_EQ:
114 case SDB_AST_NE:
115 case SDB_AST_GE:
116 case SDB_AST_GT:
117 {
118 if (analyze_node(context, op->left, errbuf))
119 return -1;
120 if (analyze_node(context, op->right, errbuf))
121 return -1;
123 if ((op->left->data_type > 0) && (op->right->data_type > 0)) {
124 if (op->left->data_type == op->right->data_type)
125 return 0;
126 op_error(errbuf, op, "type mismatch");
127 return -1;
128 }
129 if ((op->left->data_type > 0) && (op->left->data_type & SDB_TYPE_ARRAY)) {
130 op_error(errbuf, op, "array not allowed");
131 return -1;
132 }
133 if ((op->right->data_type > 0) && (op->right->data_type & SDB_TYPE_ARRAY)) {
134 op_error(errbuf, op, "array not allowed");
135 return -1;
136 }
137 break;
138 }
140 case SDB_AST_REGEX:
141 case SDB_AST_NREGEX:
142 if (analyze_node(context, op->left, errbuf))
143 return -1;
144 if (analyze_node(context, op->right, errbuf))
145 return -1;
147 /* all types are supported for the left operand
148 * TODO: introduce a cast operator if it's not a string */
149 if ((op->right->data_type > 0)
150 && (op->right->data_type != SDB_TYPE_REGEX)
151 && (op->right->data_type != SDB_TYPE_STRING)) {
152 op_error(errbuf, op, "invalid regex");
153 return -1;
154 }
155 break;
157 case SDB_AST_ISNULL:
158 case SDB_AST_ISTRUE:
159 case SDB_AST_ISFALSE:
160 if (analyze_node(context, op->right, errbuf))
161 return -1;
162 break;
164 case SDB_AST_IN:
165 if (analyze_node(context, op->left, errbuf))
166 return -1;
167 if (analyze_node(context, op->right, errbuf))
168 return -1;
170 if ((op->right->data_type > 0) && (! (op->right->data_type & SDB_TYPE_ARRAY))) {
171 op_error(errbuf, op, "array expected");
172 return -1;
173 }
174 /* the left operand may be a scalar or an array but the element
175 * type has to match */
176 if ((op->left->data_type > 0) && (op->right->data_type > 0)
177 && ((op->left->data_type & 0xff) != (op->right->data_type & 0xff))) {
178 op_error(errbuf, op, "type mismatch");
179 return -1;
180 }
181 break;
183 default:
184 sdb_strbuf_sprintf(errbuf, "Unknown operand type %d", op->kind);
185 return -1;
186 }
187 return 0;
188 } /* analyze_logical */
190 static int
191 analyze_arith(int context, sdb_ast_op_t *op, sdb_strbuf_t *errbuf)
192 {
193 if (analyze_node(context, op->left, errbuf))
194 return -1;
195 if (analyze_node(context, op->right, errbuf))
196 return -1;
197 SDB_AST_NODE(op)->data_type = sdb_data_expr_type(SDB_AST_OP_TO_DATA_OP(op->kind),
198 op->left->data_type, op->right->data_type);
200 if ((op->left->data_type > 0) && (op->right->data_type > 0)
201 && (SDB_AST_NODE(op)->data_type <= 0)) {
202 op_error(errbuf, op, "type mismatch");
203 return -1;
204 }
206 /* TODO: replace constant arithmetic operations with a constant value */
207 return 0;
208 } /* analyze_arith */
210 static int
211 analyze_iter(int context, sdb_ast_iter_t *iter, sdb_strbuf_t *errbuf)
212 {
213 sdb_ast_const_t c = SDB_AST_CONST_INIT;
214 int iter_context = context;
215 int status;
217 if (iter->iter->type == SDB_AST_TYPE_TYPED)
218 iter_context = SDB_AST_TYPED(iter->iter)->type;
220 if (analyze_node(iter_context, iter->iter, errbuf))
221 return -1;
222 /* TODO: support other setups as well */
223 assert((iter->expr->type == SDB_AST_TYPE_OPERATOR)
224 && (! SDB_AST_OP(iter->expr)->left));
225 /* determine the data-type for better error messages */
226 analyze_node(iter_context, SDB_AST_OP(iter->expr)->right, NULL);
228 if (iter->iter->type == SDB_AST_TYPE_TYPED) {
229 int iter_type = SDB_AST_TYPED(iter->iter)->type;
231 c.value.type = iter->iter->data_type;
233 if (iter_type == SDB_ATTRIBUTE) {
234 /* attributes are always iterable */
235 }
236 else if ((context != SDB_HOST) && (context != SDB_SERVICE)
237 && (context != SDB_METRIC) && (context != UNSPEC_CONTEXT)) {
238 iter_error(errbuf, iter, "%s not iterable in %s context",
239 SDB_STORE_TYPE_TO_NAME(iter_type),
240 SDB_STORE_TYPE_TO_NAME(context));
241 return -1;
242 }
244 if ((context == iter_type)
245 || ((iter_type != SDB_SERVICE)
246 && (iter_type != SDB_METRIC)
247 && (iter_type != SDB_ATTRIBUTE))
248 || ((context == SDB_SERVICE)
249 && (iter_type == SDB_METRIC))
250 || ((context == SDB_METRIC)
251 && (iter_type == SDB_SERVICE))) {
252 iter_error(errbuf, iter, "%s not iterable in %s context",
253 SDB_STORE_TYPE_TO_NAME(iter_type),
254 SDB_STORE_TYPE_TO_NAME(context));
255 return -1;
256 }
257 }
258 else if (iter->iter->type == SDB_AST_TYPE_VALUE) {
259 int iter_type = SDB_AST_VALUE(iter->iter)->type;
261 c.value.type = iter->iter->data_type & 0xff;
263 if (iter_type != SDB_FIELD_BACKEND) {
264 iter_error(errbuf, iter, "%s not iterable in %s context",
265 (iter_type == SDB_ATTRIBUTE)
266 ? "attribute"
267 : SDB_FIELD_TO_NAME(iter_type),
268 SDB_STORE_TYPE_TO_NAME(context));
269 return -1;
270 }
271 }
272 else if (iter->iter->type == SDB_AST_TYPE_CONST) {
273 c.value.type = iter->iter->data_type & 0xff;
275 if (! (SDB_AST_CONST(iter->iter)->value.type & SDB_TYPE_ARRAY)) {
276 iter_error(errbuf, iter, "%s not iterable",
277 SDB_TYPE_TO_STRING(SDB_AST_CONST(iter->iter)->value.type));
278 return -1;
279 }
280 }
281 else {
282 /* TODO: if we know the data-type of iter->iter and it's an array,
283 * we should support an iterator for it as well */
284 iter_error(errbuf, iter, "%s expression not iterable",
285 SDB_AST_TYPE_TO_STRING(iter->iter));
286 return -1;
287 }
289 SDB_AST_OP(iter->expr)->left = SDB_AST_NODE(&c);
290 status = analyze_node(context, iter->expr, errbuf);
291 SDB_AST_OP(iter->expr)->left = NULL;
292 if (status)
293 return -1;
294 return 0;
295 } /* analyze_iter */
297 static int
298 analyze_const(int __attribute__((unused)) context, sdb_ast_const_t *c,
299 sdb_strbuf_t __attribute__((unused)) *errbuf)
300 {
301 SDB_AST_NODE(c)->data_type = c->value.type;
302 return 0;
303 } /* analyze_const */
305 static int
306 analyze_value(int context, sdb_ast_value_t *v, sdb_strbuf_t *errbuf)
307 {
308 if (v->type != SDB_ATTRIBUTE)
309 SDB_AST_NODE(v)->data_type = SDB_FIELD_TYPE(v->type);
311 if ((v->type != SDB_ATTRIBUTE) && v->name) {
312 sdb_strbuf_sprintf(errbuf, "Invalid expression %s[%s]",
313 SDB_FIELD_TO_NAME(v->type), v->name);
314 return -1;
315 }
316 else if ((v->type == SDB_ATTRIBUTE) && (! v->name)) {
317 sdb_strbuf_sprintf(errbuf, "Invalid expression attribute[] "
318 "(missing name)");
319 return -1;
320 }
322 if (context != UNSPEC_CONTEXT) {
323 /* skip this check if we don't know the context; it's up to the
324 * caller to check again once the right context information is
325 * available */
326 if ((context != SDB_ATTRIBUTE) && (v->type == SDB_FIELD_VALUE)) {
327 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.value",
328 SDB_FIELD_TO_NAME(context));
329 return -1;
330 }
331 }
332 return 0;
333 } /* analyze_value */
335 static int
336 analyze_typed(int context, sdb_ast_typed_t *t, sdb_strbuf_t *errbuf)
337 {
338 if ((t->expr->type != SDB_AST_TYPE_VALUE)
339 && (t->expr->type != SDB_AST_TYPE_TYPED)) {
340 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s",
341 SDB_STORE_TYPE_TO_NAME(t->type),
342 SDB_AST_TYPE_TO_STRING(t->expr));
343 return -1;
344 }
345 if (analyze_node(t->type, t->expr, errbuf))
346 return -1;
347 SDB_AST_NODE(t)->data_type = t->expr->data_type;
349 if ((t->type != SDB_ATTRIBUTE) && (! VALID_OBJ_TYPE(t->type))) {
350 sdb_strbuf_sprintf(errbuf, "Invalid expression %#x.%s",
351 t->type, SDB_AST_TYPE_TO_STRING(t->expr));
352 return -1;
353 }
355 /* self-references are allowed and services and metrics may reference
356 * their parent host; everything may reference attributes */
357 if ((context != t->type) && (context > 0)
358 && (((context != SDB_SERVICE) && (context != SDB_METRIC))
359 || (t->type != SDB_HOST))
360 && (t->type != SDB_ATTRIBUTE)) {
361 sdb_strbuf_sprintf(errbuf, "Invalid expression %s.%s in %s context",
362 SDB_STORE_TYPE_TO_NAME(t->type),
363 SDB_AST_TYPE_TO_STRING(t->expr),
364 context == -1 ? "generic" : SDB_STORE_TYPE_TO_NAME(context));
365 return -1;
366 }
367 return 0;
368 } /* analyze_typed */
370 static int
371 analyze_node(int context, sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
372 {
373 if (! node) {
374 sdb_strbuf_sprintf(errbuf, "Empty AST node");
375 return -1;
376 }
378 /* unknown by default */
379 node->data_type = -1;
381 if ((node->type == SDB_AST_TYPE_OPERATOR)
382 && (SDB_AST_IS_LOGICAL(node)))
383 return analyze_logical(context, SDB_AST_OP(node), errbuf);
384 else if ((node->type == SDB_AST_TYPE_OPERATOR)
385 && (SDB_AST_IS_ARITHMETIC(node)))
386 return analyze_arith(context, SDB_AST_OP(node), errbuf);
387 else if (node->type == SDB_AST_TYPE_ITERATOR)
388 return analyze_iter(context, SDB_AST_ITER(node), errbuf);
389 else if (node->type == SDB_AST_TYPE_CONST)
390 return analyze_const(context, SDB_AST_CONST(node), errbuf);
391 else if (node->type == SDB_AST_TYPE_VALUE)
392 return analyze_value(context, SDB_AST_VALUE(node), errbuf);
393 else if (node->type == SDB_AST_TYPE_TYPED)
394 return analyze_typed(context, SDB_AST_TYPED(node), errbuf);
396 sdb_strbuf_sprintf(errbuf, "Invalid expression node "
397 "of type %#x", node->type);
398 return -1;
399 } /* analyze_node */
401 /*
402 * top level / command nodes
403 */
405 static int
406 analyze_fetch(sdb_ast_fetch_t *fetch, sdb_strbuf_t *errbuf)
407 {
408 if (! VALID_OBJ_TYPE(fetch->obj_type)) {
409 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
410 "in FETCH command", fetch->obj_type);
411 return -1;
412 }
413 if (! fetch->name) {
414 sdb_strbuf_sprintf(errbuf, "Missing object name in "
415 "FETCH %s command", SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
416 return -1;
417 }
419 if ((fetch->obj_type == SDB_HOST) && fetch->hostname) {
420 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
421 "in FETCH HOST command", fetch->hostname);
422 return -1;
423 }
424 else if ((fetch->obj_type != SDB_HOST) && (! fetch->hostname)) {
425 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
426 "in FETCH %s command", fetch->name,
427 SDB_STORE_TYPE_TO_NAME(fetch->obj_type));
428 return -1;
429 }
431 if (fetch->filter)
432 return analyze_node(FILTER_CONTEXT, fetch->filter, errbuf);
433 return 0;
434 } /* analyze_fetch */
436 static int
437 analyze_list(sdb_ast_list_t *list, sdb_strbuf_t *errbuf)
438 {
439 if (! VALID_OBJ_TYPE(list->obj_type)) {
440 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
441 "in LIST command", list->obj_type);
442 return -1;
443 }
444 if (list->filter)
445 return analyze_node(FILTER_CONTEXT, list->filter, errbuf);
446 return 0;
447 } /* analyze_list */
449 static int
450 analyze_lookup(sdb_ast_lookup_t *lookup, sdb_strbuf_t *errbuf)
451 {
452 if (! VALID_OBJ_TYPE(lookup->obj_type)) {
453 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
454 "in LOOKUP command", lookup->obj_type);
455 return -1;
456 }
457 if (lookup->matcher)
458 if (analyze_node(lookup->obj_type, lookup->matcher, errbuf))
459 return -1;
460 if (lookup->filter)
461 return analyze_node(FILTER_CONTEXT, lookup->filter, errbuf);
462 return 0;
463 } /* analyze_lookup */
465 static int
466 analyze_store(sdb_ast_store_t *st, sdb_strbuf_t *errbuf)
467 {
468 if ((st->obj_type != SDB_ATTRIBUTE)
469 && (! VALID_OBJ_TYPE(st->obj_type))) {
470 sdb_strbuf_sprintf(errbuf, "Invalid object type %#x "
471 "in STORE command", st->obj_type);
472 return -1;
473 }
474 if (! st->name) {
475 sdb_strbuf_sprintf(errbuf, "Missing object name in "
476 "STORE %s command", SDB_STORE_TYPE_TO_NAME(st->obj_type));
477 return -1;
478 }
480 if ((st->obj_type == SDB_HOST) && st->hostname) {
481 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
482 "in STORE HOST command", st->hostname);
483 return -1;
484 }
485 else if ((st->obj_type != SDB_HOST) && (! st->hostname)) {
486 sdb_strbuf_sprintf(errbuf, "Missing parent hostname for '%s' "
487 "in STORE %s command", st->name,
488 SDB_STORE_TYPE_TO_NAME(st->obj_type));
489 return -1;
490 }
492 if (st->obj_type == SDB_ATTRIBUTE) {
493 if ((st->parent_type <= 0) && st->parent) {
494 sdb_strbuf_sprintf(errbuf, "Unexpected parent hostname '%s' "
495 "in STORE %s command", st->parent,
496 SDB_STORE_TYPE_TO_NAME(st->obj_type));
497 return -1;
498 }
499 else if (st->parent_type > 0) {
500 if (! VALID_OBJ_TYPE(st->parent_type)) {
501 sdb_strbuf_sprintf(errbuf, "Invalid parent type %#x "
502 "in STORE %s command", st->parent_type,
503 SDB_STORE_TYPE_TO_NAME(st->obj_type));
504 return -1;
505 }
506 if (! st->parent) {
507 sdb_strbuf_sprintf(errbuf, "Missing %s parent name "
508 "in STORE %s command",
509 SDB_STORE_TYPE_TO_NAME(st->parent_type),
510 SDB_STORE_TYPE_TO_NAME(st->obj_type));
511 return -1;
512 }
513 }
514 }
515 else if ((st->parent_type > 0) || st->parent) {
516 sdb_strbuf_sprintf(errbuf, "Unexpected %s parent name '%s' "
517 "in STORE %s command",
518 SDB_STORE_TYPE_TO_NAME(st->parent_type),
519 st->parent ? st->parent : "<unknown>",
520 SDB_STORE_TYPE_TO_NAME(st->obj_type));
521 return -1;
522 }
524 if (st->obj_type == SDB_METRIC) {
525 if ((! st->store_type) != (! st->store_id)) {
526 sdb_strbuf_sprintf(errbuf, "Incomplete metric store %s %s "
527 "in STORE METRIC command",
528 st->store_type ? st->store_type : "<unknown>",
529 st->store_id ? st->store_id : "<unknown>");
530 return -1;
531 }
532 }
533 else if (st->store_type || st->store_id) {
534 sdb_strbuf_sprintf(errbuf, "Unexpected metric store %s %s "
535 "in STORE %s command",
536 st->store_type ? st->store_type : "<unknown>",
537 st->store_id ? st->store_id : "<unknown>",
538 SDB_STORE_TYPE_TO_NAME(st->obj_type));
539 return -1;
540 }
542 if ((! (st->obj_type == SDB_ATTRIBUTE))
543 && (st->value.type != SDB_TYPE_NULL)) {
544 char v_str[sdb_data_format(&st->value, NULL, 0, SDB_DOUBLE_QUOTED) + 1];
545 sdb_data_format(&st->value, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
546 sdb_strbuf_sprintf(errbuf, "Unexpected value %s in STORE %s command",
547 v_str, SDB_STORE_TYPE_TO_NAME(st->obj_type));
548 return -1;
549 }
550 return 0;
551 } /* analyze_store */
553 static int
554 analyze_timeseries(sdb_ast_timeseries_t *ts, sdb_strbuf_t *errbuf)
555 {
556 if (! ts->hostname) {
557 sdb_strbuf_sprintf(errbuf, "Missing hostname in STORE command");
558 return -1;
559 }
560 if (! ts->metric) {
561 sdb_strbuf_sprintf(errbuf, "Missing metric name in STORE command");
562 return -1;
563 }
564 if (ts->end <= ts->start) {
565 char start_str[64], end_str[64];
566 sdb_strftime(start_str, sizeof(start_str), "%F %T Tz", ts->start);
567 sdb_strftime(end_str, sizeof(end_str), "%F %T Tz", ts->end);
568 sdb_strbuf_sprintf(errbuf, "Start time (%s) greater than "
569 "end time (%s) in STORE command", start_str, end_str);
570 return -1;
571 }
572 return 0;
573 } /* analyze_timeseries */
575 /*
576 * public API
577 */
579 int
580 sdb_parser_analyze(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
581 {
582 if (! node) {
583 sdb_strbuf_sprintf(errbuf, "Empty AST node");
584 return -1;
585 }
587 /* top-level nodes don't have a type */
588 node->data_type = -1;
590 if (node->type == SDB_AST_TYPE_FETCH)
591 return analyze_fetch(SDB_AST_FETCH(node), errbuf);
592 else if (node->type == SDB_AST_TYPE_LIST)
593 return analyze_list(SDB_AST_LIST(node), errbuf);
594 else if (node->type == SDB_AST_TYPE_LOOKUP)
595 return analyze_lookup(SDB_AST_LOOKUP(node), errbuf);
596 else if (node->type == SDB_AST_TYPE_STORE)
597 return analyze_store(SDB_AST_STORE(node), errbuf);
598 else if (node->type == SDB_AST_TYPE_TIMESERIES)
599 return analyze_timeseries(SDB_AST_TIMESERIES(node), errbuf);
601 sdb_strbuf_sprintf(errbuf, "Invalid top-level AST node "
602 "of type %#x", node->type);
603 return -1;
604 } /* sdb_parser_analyze */
606 int
607 sdb_parser_analyze_conditional(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
608 {
609 if (! node) {
610 sdb_strbuf_sprintf(errbuf, "Empty conditional node");
611 return -1;
612 }
613 if (! SDB_AST_IS_LOGICAL(node)) {
614 sdb_strbuf_sprintf(errbuf, "Not a conditional node (got %s)",
615 SDB_AST_TYPE_TO_STRING(node));
616 return -1;
617 }
618 return analyze_node(UNSPEC_CONTEXT, node, errbuf);
619 } /* sdb_parser_analyze_conditional */
621 int
622 sdb_parser_analyze_arith(sdb_ast_node_t *node, sdb_strbuf_t *errbuf)
623 {
624 if (! node) {
625 sdb_strbuf_sprintf(errbuf, "Empty arithmetic node");
626 return -1;
627 }
628 if (! SDB_AST_IS_ARITHMETIC(node)) {
629 sdb_strbuf_sprintf(errbuf, "Not an arithmetic node (got %s)",
630 SDB_AST_TYPE_TO_STRING(node));
631 return -1;
632 }
633 return analyze_node(UNSPEC_CONTEXT, node, errbuf);
634 } /* sdb_parser_analyze_arith */
636 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */