source: mainline/uspace/app/bithenge/expression.c@ b8d45e9e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b8d45e9e was b8d45e9e, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: make each transform definition have its own scope

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - 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 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Expressions.
35 */
36
37#include <assert.h>
38#include <errno.h>
39#include <stdlib.h>
40#include "blob.h"
41#include "expression.h"
42#include "transform.h"
43#include "tree.h"
44
45/** Initialize a new expression.
46 * @param[out] self Expression to initialize.
47 * @param[in] ops Operations provided by the expression.
48 * @return EOK or an error code from errno.h. */
49int bithenge_init_expression(bithenge_expression_t *self,
50 const bithenge_expression_ops_t *ops)
51{
52 assert(ops);
53 assert(ops->evaluate);
54 assert(ops->destroy);
55 self->ops = ops;
56 self->refs = 1;
57 return EOK;
58}
59
60static void expression_indestructible(bithenge_expression_t *self)
61{
62 assert(false);
63}
64
65typedef struct {
66 bithenge_expression_t base;
67 bithenge_binary_op_t op;
68 bithenge_expression_t *a, *b;
69} binary_expression_t;
70
71static inline binary_expression_t *expression_as_binary(
72 bithenge_expression_t *base)
73{
74 return (binary_expression_t *)base;
75}
76
77static inline bithenge_expression_t *binary_as_expression(
78 binary_expression_t *self)
79{
80 return &self->base;
81}
82
83static int binary_expression_evaluate(bithenge_expression_t *base,
84 bithenge_scope_t *scope, bithenge_node_t **out)
85{
86 binary_expression_t *self = expression_as_binary(base);
87 bithenge_node_t *a, *b;
88 int rc = bithenge_expression_evaluate(self->a, scope, &a);
89 if (rc != EOK)
90 return rc;
91 rc = bithenge_expression_evaluate(self->b, scope, &b);
92 if (rc != EOK) {
93 bithenge_node_dec_ref(a);
94 return rc;
95 }
96 switch (self->op) {
97 case BITHENGE_EXPRESSION_EQUALS:
98 rc = bithenge_new_boolean_node(out, bithenge_node_equal(a, b));
99 break;
100 }
101 bithenge_node_dec_ref(a);
102 bithenge_node_dec_ref(b);
103 return rc;
104}
105
106static void binary_expression_destroy(bithenge_expression_t *base)
107{
108 binary_expression_t *self = expression_as_binary(base);
109 bithenge_expression_dec_ref(self->a);
110 bithenge_expression_dec_ref(self->b);
111 free(self);
112}
113
114static const bithenge_expression_ops_t binary_expression_ops = {
115 .evaluate = binary_expression_evaluate,
116 .destroy = binary_expression_destroy,
117};
118
119/** Create a binary expression. Takes ownership of @a a and @a b.
120 * @param[out] out Holds the new expression.
121 * @param op The operator to apply.
122 * @param a The first operand.
123 * @param b The second operand.
124 * @return EOK on success or an error code from errno.h. */
125int bithenge_binary_expression(bithenge_expression_t **out,
126 bithenge_binary_op_t op, bithenge_expression_t *a,
127 bithenge_expression_t *b)
128{
129 int rc;
130 binary_expression_t *self = malloc(sizeof(*self));
131 if (!self) {
132 rc = ENOMEM;
133 goto error;
134 }
135
136 rc = bithenge_init_expression(binary_as_expression(self),
137 &binary_expression_ops);
138 if (rc != EOK)
139 goto error;
140
141 self->op = op;
142 self->a = a;
143 self->b = b;
144 *out = binary_as_expression(self);
145 return EOK;
146
147error:
148 bithenge_expression_dec_ref(a);
149 bithenge_expression_dec_ref(b);
150 free(self);
151 return rc;
152}
153
154static int current_node_evaluate(bithenge_expression_t *self,
155 bithenge_scope_t *scope, bithenge_node_t **out)
156{
157 *out = bithenge_scope_get_current_node(scope);
158 if (!*out)
159 return EINVAL;
160 return EOK;
161}
162
163static const bithenge_expression_ops_t current_node_ops = {
164 .evaluate = current_node_evaluate,
165 .destroy = expression_indestructible,
166};
167
168static bithenge_expression_t current_node_expression = {
169 &current_node_ops, 1
170};
171
172/** Create an expression that gets the current node being created.
173 * @param[out] out Holds the new expression.
174 * @return EOK on success or an error code from errno.h. */
175int bithenge_current_node_expression(bithenge_expression_t **out)
176{
177 bithenge_expression_inc_ref(&current_node_expression);
178 *out = &current_node_expression;
179 return EOK;
180}
181
182typedef struct {
183 bithenge_expression_t base;
184 int index;
185} param_expression_t;
186
187static inline param_expression_t *expression_as_param(
188 bithenge_expression_t *base)
189{
190 return (param_expression_t *)base;
191}
192
193static inline bithenge_expression_t *param_as_expression(
194 param_expression_t *self)
195{
196 return &self->base;
197}
198
199static int param_expression_evaluate(bithenge_expression_t *base,
200 bithenge_scope_t *scope, bithenge_node_t **out)
201{
202 param_expression_t *self = expression_as_param(base);
203 return bithenge_scope_get_param(scope, self->index, out);
204}
205
206static void param_expression_destroy(bithenge_expression_t *base)
207{
208 param_expression_t *self = expression_as_param(base);
209 free(self);
210}
211
212static const bithenge_expression_ops_t param_expression_ops = {
213 .evaluate = param_expression_evaluate,
214 .destroy = param_expression_destroy,
215};
216
217/** Create an expression that returns a parameter.
218 * @param[out] out Holds the created expression.
219 * @param index The index of the parameter to get.
220 * @return EOK on success or an error code from errno.h. */
221int bithenge_param_expression(bithenge_expression_t **out, int index)
222{
223 int rc;
224 param_expression_t *self = malloc(sizeof(*self));
225 if (!self)
226 return ENOMEM;
227
228 rc = bithenge_init_expression(param_as_expression(self),
229 &param_expression_ops);
230 if (rc != EOK) {
231 free(self);
232 return rc;
233 }
234
235 self->index = index;
236 *out = param_as_expression(self);
237 return EOK;
238}
239
240typedef struct {
241 bithenge_expression_t base;
242 bithenge_node_t *node;
243} const_expression_t;
244
245static inline const_expression_t *expression_as_const(
246 bithenge_expression_t *base)
247{
248 return (const_expression_t *)base;
249}
250
251static inline bithenge_expression_t *const_as_expression(
252 const_expression_t *self)
253{
254 return &self->base;
255}
256
257static int const_expression_evaluate(bithenge_expression_t *base,
258 bithenge_scope_t *scope, bithenge_node_t **out)
259{
260 const_expression_t *self = expression_as_const(base);
261 bithenge_node_inc_ref(self->node);
262 *out = self->node;
263 return EOK;
264}
265
266static void const_expression_destroy(bithenge_expression_t *base)
267{
268 const_expression_t *self = expression_as_const(base);
269 bithenge_node_dec_ref(self->node);
270 free(self);
271}
272
273static const bithenge_expression_ops_t const_expression_ops = {
274 .evaluate = const_expression_evaluate,
275 .destroy = const_expression_destroy,
276};
277
278/** Create an expression that returns a constant. Takes a reference to @a node.
279 * @param[out] out Holds the created expression.
280 * @param node The constant.
281 * @return EOK on success or an error code from errno.h. */
282int bithenge_const_expression(bithenge_expression_t **out,
283 bithenge_node_t *node)
284{
285 int rc;
286 const_expression_t *self = malloc(sizeof(*self));
287 if (!self) {
288 rc = ENOMEM;
289 goto error;
290 }
291
292 rc = bithenge_init_expression(const_as_expression(self),
293 &const_expression_ops);
294 if (rc != EOK)
295 goto error;
296
297 self->node = node;
298 *out = const_as_expression(self);
299 return EOK;
300
301error:
302 free(self);
303 bithenge_node_dec_ref(node);
304 return rc;
305}
306
307typedef struct {
308 bithenge_expression_t base;
309 bithenge_expression_t *expr;
310 bithenge_node_t *key;
311} member_expression_t;
312
313static member_expression_t *expression_as_member(bithenge_expression_t *base)
314{
315 return (member_expression_t *)base;
316}
317
318static bithenge_expression_t *member_as_expression(member_expression_t *expr)
319{
320 return &expr->base;
321}
322
323static int member_expression_evaluate(bithenge_expression_t *base,
324 bithenge_scope_t *scope, bithenge_node_t **out)
325{
326 member_expression_t *self = expression_as_member(base);
327 bithenge_node_t *node;
328 int rc = bithenge_expression_evaluate(self->expr, scope, &node);
329 if (rc != EOK)
330 return rc;
331 bithenge_node_inc_ref(self->key);
332 rc = bithenge_node_get(node, self->key, out);
333 bithenge_node_dec_ref(node);
334 return rc;
335}
336
337static void member_expression_destroy(bithenge_expression_t *base)
338{
339 member_expression_t *self = expression_as_member(base);
340 bithenge_expression_dec_ref(self->expr);
341 bithenge_node_dec_ref(self->key);
342 free(self);
343}
344
345static const bithenge_expression_ops_t member_expression_ops = {
346 .evaluate = member_expression_evaluate,
347 .destroy = member_expression_destroy,
348};
349
350/** Create an expression that gets a member from a node. Takes references to
351 * @a expr and @a key.
352 * @param[out] out Holds the new expression.
353 * @param expr Calculates the node to get the member of.
354 * @param key The member to get.
355 * @return EOK on success or an error code from errno.h. */
356int bithenge_member_expression(bithenge_expression_t **out,
357 bithenge_expression_t *expr, bithenge_node_t *key)
358{
359 int rc;
360 member_expression_t *self = malloc(sizeof(*self));
361 if (!self) {
362 rc = ENOMEM;
363 goto error;
364 }
365
366 rc = bithenge_init_expression(member_as_expression(self),
367 &member_expression_ops);
368 if (rc != EOK)
369 goto error;
370
371 self->expr = expr;
372 self->key = key;
373 *out = member_as_expression(self);
374 return EOK;
375
376error:
377 bithenge_expression_dec_ref(expr);
378 bithenge_node_dec_ref(key);
379 free(self);
380 return rc;
381}
382
383typedef struct {
384 bithenge_transform_t base;
385 bithenge_transform_t *transform;
386 bithenge_expression_t **params;
387} param_wrapper_t;
388
389static inline bithenge_transform_t *param_wrapper_as_transform(
390 param_wrapper_t *self)
391{
392 return &self->base;
393}
394
395static inline param_wrapper_t *transform_as_param_wrapper(
396 bithenge_transform_t *base)
397{
398 return (param_wrapper_t *)base;
399}
400
401static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
402 *inner, bithenge_scope_t *outer)
403{
404 int rc;
405 int num_params = bithenge_transform_num_params(self->transform);
406 rc = bithenge_scope_alloc_params(inner, num_params);
407 if (rc != EOK)
408 return rc;
409 for (int i = 0; i < num_params; i++) {
410 bithenge_node_t *node;
411 rc = bithenge_expression_evaluate(self->params[i], outer,
412 &node);
413 if (rc != EOK)
414 return rc;
415 rc = bithenge_scope_set_param(inner, i, node);
416 if (rc != EOK)
417 return rc;
418 }
419 return EOK;
420}
421
422static int param_wrapper_apply(bithenge_transform_t *base,
423 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
424{
425 param_wrapper_t *self = transform_as_param_wrapper(base);
426 bithenge_scope_t inner;
427 bithenge_scope_init(&inner);
428 int rc = param_wrapper_fill_scope(self, &inner, outer);
429 if (rc != EOK)
430 goto error;
431
432 rc = bithenge_transform_apply(self->transform, &inner, in, out);
433 in = NULL;
434
435error:
436 bithenge_scope_destroy(&inner);
437 return rc;
438}
439
440static int param_wrapper_prefix_length(bithenge_transform_t *base,
441 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
442{
443 param_wrapper_t *self = transform_as_param_wrapper(base);
444 bithenge_scope_t inner;
445 bithenge_scope_init(&inner);
446 int rc = param_wrapper_fill_scope(self, &inner, outer);
447 if (rc != EOK)
448 goto error;
449
450 rc = bithenge_transform_prefix_length(self->transform, &inner, in,
451 out);
452 in = NULL;
453
454error:
455 bithenge_scope_destroy(&inner);
456 return rc;
457}
458
459static void param_wrapper_destroy(bithenge_transform_t *base)
460{
461 param_wrapper_t *self = transform_as_param_wrapper(base);
462 int num_params = bithenge_transform_num_params(self->transform);
463 bithenge_transform_dec_ref(self->transform);
464 for (int i = 0; i < num_params; i++)
465 bithenge_expression_dec_ref(self->params[i]);
466 free(self->params);
467 free(self);
468}
469
470static const bithenge_transform_ops_t param_wrapper_ops = {
471 .apply = param_wrapper_apply,
472 .prefix_length = param_wrapper_prefix_length,
473 .destroy = param_wrapper_destroy,
474};
475
476/** Create a transform that calculates parameters for another transform. Takes
477 * ownership of @a transform, @a params, and each element of @a params. The
478 * number of parameters must be correct.
479 * @param[out] out Holds the new transform.
480 * @param transform The transform for which parameters are calculated.
481 * @param params The expressions used to calculate the parameters.
482 * @return EOK on success or an error code from errno.h. */
483int bithenge_param_wrapper(bithenge_transform_t **out,
484 bithenge_transform_t *transform, bithenge_expression_t **params)
485{
486 int rc;
487 int num_params = bithenge_transform_num_params(transform);
488 param_wrapper_t *self = malloc(sizeof(*self));
489 if (!self) {
490 rc = ENOMEM;
491 goto error;
492 }
493
494 rc = bithenge_init_transform(param_wrapper_as_transform(self),
495 &param_wrapper_ops, 0);
496 if (rc != EOK)
497 goto error;
498
499 self->transform = transform;
500 self->params = params;
501 *out = param_wrapper_as_transform(self);
502 return EOK;
503
504error:
505 free(self);
506 for (int i = 0; i < num_params; i++)
507 bithenge_expression_dec_ref(params[i]);
508 free(params);
509 bithenge_transform_dec_ref(transform);
510 return rc;
511}
512
513typedef struct {
514 bithenge_transform_t base;
515 bithenge_expression_t *expr;
516} expression_transform_t;
517
518static inline bithenge_transform_t *expression_as_transform(
519 expression_transform_t *self)
520{
521 return &self->base;
522}
523
524static inline expression_transform_t *transform_as_expression(
525 bithenge_transform_t *base)
526{
527 return (expression_transform_t *)base;
528}
529
530static int expression_transform_apply(bithenge_transform_t *base,
531 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
532{
533 expression_transform_t *self = transform_as_expression(base);
534 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
535 return EINVAL;
536 aoff64_t len;
537 int rc = bithenge_blob_size(bithenge_node_as_blob(in), &len);
538 if (rc != EOK)
539 return rc;
540 if (len != 0)
541 return EINVAL;
542 return bithenge_expression_evaluate(self->expr, scope, out);
543}
544
545static int expression_transform_prefix_length(bithenge_transform_t *base,
546 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
547{
548 *out = 0;
549 return EOK;
550}
551
552static void expression_transform_destroy(bithenge_transform_t *base)
553{
554 expression_transform_t *self = transform_as_expression(base);
555 bithenge_expression_dec_ref(self->expr);
556 free(self);
557}
558
559static const bithenge_transform_ops_t expression_transform_ops = {
560 .apply = expression_transform_apply,
561 .prefix_length = expression_transform_prefix_length,
562 .destroy = expression_transform_destroy,
563};
564
565/** Create a transform that takes an empty blob and produces the result of an
566 * expression. Takes a reference to the expression.
567 * @param[out] out Holds the new transform.
568 * @param expr The expression to evaluate.
569 * @return EOK on success or an error code from errno.h. */
570int bithenge_expression_transform(bithenge_transform_t ** out,
571 bithenge_expression_t *expr)
572{
573 int rc;
574 expression_transform_t *self = malloc(sizeof(*self));
575 if (!self) {
576 rc = ENOMEM;
577 goto error;
578 }
579
580 rc = bithenge_init_transform(expression_as_transform(self),
581 &expression_transform_ops, 0);
582 if (rc != EOK)
583 goto error;
584
585 self->expr = expr;
586 *out = expression_as_transform(self);
587 return EOK;
588
589error:
590 free(self);
591 bithenge_expression_dec_ref(expr);
592 return rc;
593}
594
595typedef struct {
596 bithenge_transform_t base;
597 bithenge_expression_t *expr;
598 bithenge_transform_t *true_xform, *false_xform;
599} if_transform_t;
600
601static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
602{
603 return &self->base;
604}
605
606static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
607{
608 return (if_transform_t *)base;
609}
610
611static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
612 bool *out)
613{
614 bithenge_node_t *cond_node;
615 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
616 if (rc != EOK)
617 return rc;
618 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
619 bithenge_node_dec_ref(cond_node);
620 return EINVAL;
621 }
622 *out = bithenge_boolean_node_value(cond_node);
623 bithenge_node_dec_ref(cond_node);
624 return EOK;
625}
626
627static int if_transform_apply(bithenge_transform_t *base,
628 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
629{
630 if_transform_t *self = transform_as_if(base);
631 bool cond;
632 int rc = if_transform_choose(self, scope, &cond);
633 if (rc != EOK)
634 return rc;
635 return bithenge_transform_apply(
636 cond ? self->true_xform : self->false_xform, scope, in, out);
637}
638
639static int if_transform_prefix_length(bithenge_transform_t *base,
640 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
641{
642 if_transform_t *self = transform_as_if(base);
643 bool cond;
644 int rc = if_transform_choose(self, scope, &cond);
645 if (rc != EOK)
646 return rc;
647 return bithenge_transform_prefix_length(
648 cond ? self->true_xform : self->false_xform, scope, in, out);
649}
650
651static void if_transform_destroy(bithenge_transform_t *base)
652{
653 if_transform_t *self = transform_as_if(base);
654 bithenge_expression_dec_ref(self->expr);
655 bithenge_transform_dec_ref(self->true_xform);
656 bithenge_transform_dec_ref(self->false_xform);
657 free(self);
658}
659
660static const bithenge_transform_ops_t if_transform_ops = {
661 .apply = if_transform_apply,
662 .prefix_length = if_transform_prefix_length,
663 .destroy = if_transform_destroy,
664};
665
666/** Create a transform that applies either of two transforms depending on a
667 * boolean expression. Takes references to @a expr, @a true_xform, and
668 * @a false_xform.
669 * @param[out] out Holds the new transform.
670 * @param expr The boolean expression to evaluate.
671 * @param true_xform The transform to apply if the expression is true.
672 * @param false_xform The transform to apply if the expression is false.
673 * @return EOK on success or an error code from errno.h. */
674int bithenge_if_transform(bithenge_transform_t **out,
675 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
676 bithenge_transform_t *false_xform)
677{
678 int rc;
679 if_transform_t *self = malloc(sizeof(*self));
680 if (!self) {
681 rc = ENOMEM;
682 goto error;
683 }
684
685 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
686 0);
687 if (rc != EOK)
688 goto error;
689
690 self->expr = expr;
691 self->true_xform = true_xform;
692 self->false_xform = false_xform;
693 *out = if_as_transform(self);
694 return EOK;
695
696error:
697 free(self);
698 bithenge_expression_dec_ref(expr);
699 bithenge_transform_dec_ref(true_xform);
700 bithenge_transform_dec_ref(false_xform);
701 return rc;
702}
703
704/** @}
705 */
Note: See TracBrowser for help on using the repository browser.