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

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

Bithenge: use expressions to make transforms

  • Property mode set to 100644
File size: 24.6 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
65
66
67/***************** binary_expression *****************/
68
69typedef struct {
70 bithenge_expression_t base;
71 bithenge_binary_op_t op;
72 bithenge_expression_t *a, *b;
73} binary_expression_t;
74
75static inline binary_expression_t *expression_as_binary(
76 bithenge_expression_t *base)
77{
78 return (binary_expression_t *)base;
79}
80
81static inline bithenge_expression_t *binary_as_expression(
82 binary_expression_t *self)
83{
84 return &self->base;
85}
86
87static int binary_expression_evaluate(bithenge_expression_t *base,
88 bithenge_scope_t *scope, bithenge_node_t **out)
89{
90 binary_expression_t *self = expression_as_binary(base);
91 bithenge_node_t *a, *b;
92 int rc = bithenge_expression_evaluate(self->a, scope, &a);
93 if (rc != EOK)
94 return rc;
95 rc = bithenge_expression_evaluate(self->b, scope, &b);
96 if (rc != EOK) {
97 bithenge_node_dec_ref(a);
98 return rc;
99 }
100
101 /* Check types and get values. */
102 bithenge_int_t a_int, b_int;
103 switch (self->op) {
104 case BITHENGE_EXPRESSION_ADD: /* fallthrough */
105 case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
106 case BITHENGE_EXPRESSION_MULTIPLY:
107 rc = EINVAL;
108 if (bithenge_node_type(a) != BITHENGE_NODE_INTEGER)
109 goto error;
110 if (bithenge_node_type(b) != BITHENGE_NODE_INTEGER)
111 goto error;
112 a_int = bithenge_integer_node_value(a);
113 b_int = bithenge_integer_node_value(b);
114 break;
115 default:
116 break;
117 }
118
119 switch (self->op) {
120 case BITHENGE_EXPRESSION_ADD:
121 rc = bithenge_new_integer_node(out, a_int + b_int);
122 break;
123 case BITHENGE_EXPRESSION_SUBTRACT:
124 rc = bithenge_new_integer_node(out, a_int - b_int);
125 break;
126 case BITHENGE_EXPRESSION_MULTIPLY:
127 rc = bithenge_new_integer_node(out, a_int * b_int);
128 break;
129 case BITHENGE_EXPRESSION_EQUALS:
130 rc = bithenge_new_boolean_node(out, bithenge_node_equal(a, b));
131 break;
132 case BITHENGE_EXPRESSION_INVALID_BINARY_OP:
133 assert(false);
134 break;
135 }
136
137error:
138 bithenge_node_dec_ref(a);
139 bithenge_node_dec_ref(b);
140 return rc;
141}
142
143static void binary_expression_destroy(bithenge_expression_t *base)
144{
145 binary_expression_t *self = expression_as_binary(base);
146 bithenge_expression_dec_ref(self->a);
147 bithenge_expression_dec_ref(self->b);
148 free(self);
149}
150
151static const bithenge_expression_ops_t binary_expression_ops = {
152 .evaluate = binary_expression_evaluate,
153 .destroy = binary_expression_destroy,
154};
155
156/** Create a binary expression. Takes ownership of @a a and @a b.
157 * @param[out] out Holds the new expression.
158 * @param op The operator to apply.
159 * @param a The first operand.
160 * @param b The second operand.
161 * @return EOK on success or an error code from errno.h. */
162int bithenge_binary_expression(bithenge_expression_t **out,
163 bithenge_binary_op_t op, bithenge_expression_t *a,
164 bithenge_expression_t *b)
165{
166 int rc;
167 binary_expression_t *self = malloc(sizeof(*self));
168 if (!self) {
169 rc = ENOMEM;
170 goto error;
171 }
172
173 rc = bithenge_init_expression(binary_as_expression(self),
174 &binary_expression_ops);
175 if (rc != EOK)
176 goto error;
177
178 self->op = op;
179 self->a = a;
180 self->b = b;
181 *out = binary_as_expression(self);
182 return EOK;
183
184error:
185 bithenge_expression_dec_ref(a);
186 bithenge_expression_dec_ref(b);
187 free(self);
188 return rc;
189}
190
191
192
193/***************** in_node_expression *****************/
194
195static int in_node_evaluate(bithenge_expression_t *self,
196 bithenge_scope_t *scope, bithenge_node_t **out)
197{
198 for (; scope && !bithenge_scope_is_barrier(scope);
199 scope = bithenge_scope_outer(scope)) {
200 *out = bithenge_scope_in_node(scope);
201 if (*out)
202 return EOK;
203 }
204 return EINVAL;
205}
206
207static const bithenge_expression_ops_t in_node_ops = {
208 .evaluate = in_node_evaluate,
209 .destroy = expression_indestructible,
210};
211
212static bithenge_expression_t in_node_expression = {
213 &in_node_ops, 1
214};
215
216/** Create an expression that gets the current input node.
217 * @param[out] out Holds the new expression.
218 * @return EOK on success or an error code from errno.h. */
219int bithenge_in_node_expression(bithenge_expression_t **out)
220{
221 bithenge_expression_inc_ref(&in_node_expression);
222 *out = &in_node_expression;
223 return EOK;
224}
225
226
227
228/***************** current_node_expression *****************/
229
230static int current_node_evaluate(bithenge_expression_t *self,
231 bithenge_scope_t *scope, bithenge_node_t **out)
232{
233 *out = bithenge_scope_get_current_node(scope);
234 if (!*out)
235 return EINVAL;
236 return EOK;
237}
238
239static const bithenge_expression_ops_t current_node_ops = {
240 .evaluate = current_node_evaluate,
241 .destroy = expression_indestructible,
242};
243
244static bithenge_expression_t current_node_expression = {
245 &current_node_ops, 1
246};
247
248/** Create an expression that gets the current node being created.
249 * @param[out] out Holds the new expression.
250 * @return EOK on success or an error code from errno.h. */
251int bithenge_current_node_expression(bithenge_expression_t **out)
252{
253 bithenge_expression_inc_ref(&current_node_expression);
254 *out = &current_node_expression;
255 return EOK;
256}
257
258
259
260/***************** param_expression *****************/
261
262typedef struct {
263 bithenge_expression_t base;
264 int index;
265} param_expression_t;
266
267static inline param_expression_t *expression_as_param(
268 bithenge_expression_t *base)
269{
270 return (param_expression_t *)base;
271}
272
273static inline bithenge_expression_t *param_as_expression(
274 param_expression_t *self)
275{
276 return &self->base;
277}
278
279static int param_expression_evaluate(bithenge_expression_t *base,
280 bithenge_scope_t *scope, bithenge_node_t **out)
281{
282 param_expression_t *self = expression_as_param(base);
283 return bithenge_scope_get_param(scope, self->index, out);
284}
285
286static void param_expression_destroy(bithenge_expression_t *base)
287{
288 param_expression_t *self = expression_as_param(base);
289 free(self);
290}
291
292static const bithenge_expression_ops_t param_expression_ops = {
293 .evaluate = param_expression_evaluate,
294 .destroy = param_expression_destroy,
295};
296
297/** Create an expression that returns a parameter.
298 * @param[out] out Holds the created expression.
299 * @param index The index of the parameter to get.
300 * @return EOK on success or an error code from errno.h. */
301int bithenge_param_expression(bithenge_expression_t **out, int index)
302{
303 int rc;
304 param_expression_t *self = malloc(sizeof(*self));
305 if (!self)
306 return ENOMEM;
307
308 rc = bithenge_init_expression(param_as_expression(self),
309 &param_expression_ops);
310 if (rc != EOK) {
311 free(self);
312 return rc;
313 }
314
315 self->index = index;
316 *out = param_as_expression(self);
317 return EOK;
318}
319
320
321
322/***************** const_expression *****************/
323
324typedef struct {
325 bithenge_expression_t base;
326 bithenge_node_t *node;
327} const_expression_t;
328
329static inline const_expression_t *expression_as_const(
330 bithenge_expression_t *base)
331{
332 return (const_expression_t *)base;
333}
334
335static inline bithenge_expression_t *const_as_expression(
336 const_expression_t *self)
337{
338 return &self->base;
339}
340
341static int const_expression_evaluate(bithenge_expression_t *base,
342 bithenge_scope_t *scope, bithenge_node_t **out)
343{
344 const_expression_t *self = expression_as_const(base);
345 bithenge_node_inc_ref(self->node);
346 *out = self->node;
347 return EOK;
348}
349
350static void const_expression_destroy(bithenge_expression_t *base)
351{
352 const_expression_t *self = expression_as_const(base);
353 bithenge_node_dec_ref(self->node);
354 free(self);
355}
356
357static const bithenge_expression_ops_t const_expression_ops = {
358 .evaluate = const_expression_evaluate,
359 .destroy = const_expression_destroy,
360};
361
362/** Create an expression that returns a constant. Takes a reference to @a node.
363 * @param[out] out Holds the created expression.
364 * @param node The constant.
365 * @return EOK on success or an error code from errno.h. */
366int bithenge_const_expression(bithenge_expression_t **out,
367 bithenge_node_t *node)
368{
369 int rc;
370 const_expression_t *self = malloc(sizeof(*self));
371 if (!self) {
372 rc = ENOMEM;
373 goto error;
374 }
375
376 rc = bithenge_init_expression(const_as_expression(self),
377 &const_expression_ops);
378 if (rc != EOK)
379 goto error;
380
381 self->node = node;
382 *out = const_as_expression(self);
383 return EOK;
384
385error:
386 free(self);
387 bithenge_node_dec_ref(node);
388 return rc;
389}
390
391
392
393/***************** member_expression *****************/
394
395typedef struct {
396 bithenge_expression_t base;
397 bithenge_expression_t *expr;
398 bithenge_node_t *key;
399} member_expression_t;
400
401static member_expression_t *expression_as_member(bithenge_expression_t *base)
402{
403 return (member_expression_t *)base;
404}
405
406static bithenge_expression_t *member_as_expression(member_expression_t *expr)
407{
408 return &expr->base;
409}
410
411static int member_expression_evaluate(bithenge_expression_t *base,
412 bithenge_scope_t *scope, bithenge_node_t **out)
413{
414 member_expression_t *self = expression_as_member(base);
415 bithenge_node_t *node;
416 int rc = bithenge_expression_evaluate(self->expr, scope, &node);
417 if (rc != EOK)
418 return rc;
419 bithenge_node_inc_ref(self->key);
420 rc = bithenge_node_get(node, self->key, out);
421 bithenge_node_dec_ref(node);
422 return rc;
423}
424
425static void member_expression_destroy(bithenge_expression_t *base)
426{
427 member_expression_t *self = expression_as_member(base);
428 bithenge_expression_dec_ref(self->expr);
429 bithenge_node_dec_ref(self->key);
430 free(self);
431}
432
433static const bithenge_expression_ops_t member_expression_ops = {
434 .evaluate = member_expression_evaluate,
435 .destroy = member_expression_destroy,
436};
437
438/** Create an expression that gets a member from a node. Takes references to
439 * @a expr and @a key.
440 * @param[out] out Holds the new expression.
441 * @param expr Calculates the node to get the member of.
442 * @param key The member to get.
443 * @return EOK on success or an error code from errno.h. */
444int bithenge_member_expression(bithenge_expression_t **out,
445 bithenge_expression_t *expr, bithenge_node_t *key)
446{
447 int rc;
448 member_expression_t *self = malloc(sizeof(*self));
449 if (!self) {
450 rc = ENOMEM;
451 goto error;
452 }
453
454 rc = bithenge_init_expression(member_as_expression(self),
455 &member_expression_ops);
456 if (rc != EOK)
457 goto error;
458
459 self->expr = expr;
460 self->key = key;
461 *out = member_as_expression(self);
462 return EOK;
463
464error:
465 bithenge_expression_dec_ref(expr);
466 bithenge_node_dec_ref(key);
467 free(self);
468 return rc;
469}
470
471
472
473/***************** scope_member_expression *****************/
474
475typedef struct {
476 bithenge_expression_t base;
477 bithenge_node_t *key;
478} scope_member_expression_t;
479
480static scope_member_expression_t *expression_as_scope_member(
481 bithenge_expression_t *base)
482{
483 return (scope_member_expression_t *)base;
484}
485
486static bithenge_expression_t *scope_member_as_expression(
487 scope_member_expression_t *expr)
488{
489 return &expr->base;
490}
491
492static int scope_member_expression_evaluate(bithenge_expression_t *base,
493 bithenge_scope_t *scope, bithenge_node_t **out)
494{
495 scope_member_expression_t *self = expression_as_scope_member(base);
496 for (; scope && !bithenge_scope_is_barrier(scope);
497 scope = bithenge_scope_outer(scope)) {
498 bithenge_node_inc_ref(self->key);
499 bithenge_node_t *cur = bithenge_scope_get_current_node(scope);
500 int rc = bithenge_node_get(cur, self->key, out);
501 bithenge_node_dec_ref(cur);
502 if (rc != ENOENT) /* EOK or error */
503 return rc;
504 }
505 return ENOENT;
506}
507
508static void scope_member_expression_destroy(bithenge_expression_t *base)
509{
510 scope_member_expression_t *self = expression_as_scope_member(base);
511 bithenge_node_dec_ref(self->key);
512 free(self);
513}
514
515static const bithenge_expression_ops_t scope_member_expression_ops = {
516 .evaluate = scope_member_expression_evaluate,
517 .destroy = scope_member_expression_destroy,
518};
519
520int bithenge_scope_member_expression(bithenge_expression_t **out,
521 bithenge_node_t *key)
522{
523 int rc;
524 scope_member_expression_t *self = malloc(sizeof(*self));
525 if (!self) {
526 rc = ENOMEM;
527 goto error;
528 }
529
530 rc = bithenge_init_expression(scope_member_as_expression(self),
531 &scope_member_expression_ops);
532 if (rc != EOK)
533 goto error;
534
535 self->key = key;
536 *out = scope_member_as_expression(self);
537 return EOK;
538
539error:
540 bithenge_node_dec_ref(key);
541 free(self);
542 return rc;
543}
544
545
546
547/***************** param_wrapper *****************/
548
549typedef struct {
550 bithenge_transform_t base;
551 bithenge_transform_t *transform;
552 bithenge_expression_t **params;
553} param_wrapper_t;
554
555static inline bithenge_transform_t *param_wrapper_as_transform(
556 param_wrapper_t *self)
557{
558 return &self->base;
559}
560
561static inline param_wrapper_t *transform_as_param_wrapper(
562 bithenge_transform_t *base)
563{
564 return (param_wrapper_t *)base;
565}
566
567static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
568 *inner, bithenge_scope_t *outer)
569{
570 int rc;
571 int num_params = bithenge_transform_num_params(self->transform);
572 rc = bithenge_scope_alloc_params(inner, num_params);
573 if (rc != EOK)
574 return rc;
575 for (int i = 0; i < num_params; i++) {
576 bithenge_node_t *node;
577 rc = bithenge_expression_evaluate(self->params[i], outer,
578 &node);
579 if (rc != EOK)
580 return rc;
581 rc = bithenge_scope_set_param(inner, i, node);
582 if (rc != EOK)
583 return rc;
584 }
585 return EOK;
586}
587
588static int param_wrapper_apply(bithenge_transform_t *base,
589 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
590{
591 param_wrapper_t *self = transform_as_param_wrapper(base);
592 bithenge_scope_t *inner;
593 int rc = bithenge_scope_new(&inner, outer);
594 if (rc != EOK)
595 return rc;
596 rc = param_wrapper_fill_scope(self, inner, outer);
597 if (rc != EOK)
598 goto error;
599
600 rc = bithenge_transform_apply(self->transform, inner, in, out);
601 in = NULL;
602
603error:
604 bithenge_scope_dec_ref(inner);
605 return rc;
606}
607
608static int param_wrapper_prefix_length(bithenge_transform_t *base,
609 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
610{
611 param_wrapper_t *self = transform_as_param_wrapper(base);
612 bithenge_scope_t *inner;
613 int rc = bithenge_scope_new(&inner, outer);
614 if (rc != EOK)
615 return rc;
616 rc = param_wrapper_fill_scope(self, inner, outer);
617 if (rc != EOK)
618 goto error;
619
620 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
621 in = NULL;
622
623error:
624 bithenge_scope_dec_ref(inner);
625 return rc;
626}
627
628static int param_wrapper_prefix_apply(bithenge_transform_t *base,
629 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
630 aoff64_t *out_length)
631{
632 param_wrapper_t *self = transform_as_param_wrapper(base);
633 bithenge_scope_t *inner;
634 int rc = bithenge_scope_new(&inner, outer);
635 if (rc != EOK)
636 return rc;
637 rc = param_wrapper_fill_scope(self, inner, outer);
638 if (rc != EOK)
639 goto error;
640
641 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
642 out_node, out_length);
643
644error:
645 bithenge_scope_dec_ref(inner);
646 return rc;
647}
648
649static void param_wrapper_destroy(bithenge_transform_t *base)
650{
651 param_wrapper_t *self = transform_as_param_wrapper(base);
652 int num_params = bithenge_transform_num_params(self->transform);
653 bithenge_transform_dec_ref(self->transform);
654 for (int i = 0; i < num_params; i++)
655 bithenge_expression_dec_ref(self->params[i]);
656 free(self->params);
657 free(self);
658}
659
660static const bithenge_transform_ops_t param_wrapper_ops = {
661 .apply = param_wrapper_apply,
662 .prefix_length = param_wrapper_prefix_length,
663 .prefix_apply = param_wrapper_prefix_apply,
664 .destroy = param_wrapper_destroy,
665};
666
667/** Create a transform that calculates parameters for another transform. Takes
668 * ownership of @a transform, @a params, and each element of @a params. The
669 * number of parameters must be correct.
670 * @param[out] out Holds the new transform.
671 * @param transform The transform for which parameters are calculated.
672 * @param params The expressions used to calculate the parameters.
673 * @return EOK on success or an error code from errno.h. */
674int bithenge_param_wrapper(bithenge_transform_t **out,
675 bithenge_transform_t *transform, bithenge_expression_t **params)
676{
677 int rc;
678 int num_params = bithenge_transform_num_params(transform);
679 param_wrapper_t *self = malloc(sizeof(*self));
680 if (!self) {
681 rc = ENOMEM;
682 goto error;
683 }
684
685 rc = bithenge_init_transform(param_wrapper_as_transform(self),
686 &param_wrapper_ops, 0);
687 if (rc != EOK)
688 goto error;
689
690 self->transform = transform;
691 self->params = params;
692 *out = param_wrapper_as_transform(self);
693 return EOK;
694
695error:
696 free(self);
697 for (int i = 0; i < num_params; i++)
698 bithenge_expression_dec_ref(params[i]);
699 free(params);
700 bithenge_transform_dec_ref(transform);
701 return rc;
702}
703
704
705
706/***************** expression_transform *****************/
707
708/* Also used by inputless_transform. */
709typedef struct {
710 bithenge_transform_t base;
711 bithenge_expression_t *expr;
712} expression_transform_t;
713
714static inline bithenge_transform_t *expression_as_transform(
715 expression_transform_t *self)
716{
717 return &self->base;
718}
719
720static inline expression_transform_t *transform_as_expression(
721 bithenge_transform_t *base)
722{
723 return (expression_transform_t *)base;
724}
725
726static int expression_transform_apply(bithenge_transform_t *base,
727 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
728{
729 expression_transform_t *self = transform_as_expression(base);
730 bithenge_scope_t *inner;
731 int rc = bithenge_scope_new(&inner, scope);
732 if (rc != EOK)
733 return rc;
734 bithenge_scope_set_in_node(inner, in);
735 rc = bithenge_expression_evaluate(self->expr, inner, out);
736 bithenge_scope_dec_ref(inner);
737 return rc;
738}
739
740/* Also used by inputless_transform. */
741static void expression_transform_destroy(bithenge_transform_t *base)
742{
743 expression_transform_t *self = transform_as_expression(base);
744 bithenge_expression_dec_ref(self->expr);
745 free(self);
746}
747
748static const bithenge_transform_ops_t expression_transform_ops = {
749 .apply = expression_transform_apply,
750 .destroy = expression_transform_destroy,
751};
752
753/** Create a transform that evaluates an expression on the input node. Takes a
754 * reference to the expression.
755 * @param[out] out Holds the new transform.
756 * @param expr The expression to evaluate.
757 * @return EOK on success or an error code from errno.h. */
758int bithenge_expression_transform(bithenge_transform_t ** out,
759 bithenge_expression_t *expr)
760{
761 int rc;
762 expression_transform_t *self = malloc(sizeof(*self));
763 if (!self) {
764 rc = ENOMEM;
765 goto error;
766 }
767
768 rc = bithenge_init_transform(expression_as_transform(self),
769 &expression_transform_ops, 0);
770 if (rc != EOK)
771 goto error;
772
773 self->expr = expr;
774 *out = expression_as_transform(self);
775 return EOK;
776
777error:
778 free(self);
779 bithenge_expression_dec_ref(expr);
780 return rc;
781}
782
783
784
785/***************** inputless_transform *****************/
786
787static int inputless_transform_prefix_length(bithenge_transform_t *base,
788 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
789{
790 *out = 0;
791 return EOK;
792}
793
794static int inputless_transform_prefix_apply(bithenge_transform_t *base,
795 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
796 aoff64_t *out_size)
797{
798 expression_transform_t *self = transform_as_expression(base);
799 *out_size = 0;
800 return bithenge_expression_evaluate(self->expr, scope, out_node);
801}
802
803static const bithenge_transform_ops_t inputless_transform_ops = {
804 .prefix_length = inputless_transform_prefix_length,
805 .prefix_apply = inputless_transform_prefix_apply,
806 .destroy = expression_transform_destroy,
807};
808
809/** Create a transform that takes an empty blob and produces the result of an
810 * expression. Takes a reference to the expression.
811 * @param[out] out Holds the new transform.
812 * @param expr The expression to evaluate.
813 * @return EOK on success or an error code from errno.h. */
814int bithenge_inputless_transform(bithenge_transform_t ** out,
815 bithenge_expression_t *expr)
816{
817 int rc;
818 expression_transform_t *self = malloc(sizeof(*self));
819 if (!self) {
820 rc = ENOMEM;
821 goto error;
822 }
823
824 rc = bithenge_init_transform(expression_as_transform(self),
825 &inputless_transform_ops, 0);
826 if (rc != EOK)
827 goto error;
828
829 self->expr = expr;
830 *out = expression_as_transform(self);
831 return EOK;
832
833error:
834 free(self);
835 bithenge_expression_dec_ref(expr);
836 return rc;
837}
838
839
840
841/***************** if_transform *****************/
842
843typedef struct {
844 bithenge_transform_t base;
845 bithenge_expression_t *expr;
846 bithenge_transform_t *true_xform, *false_xform;
847} if_transform_t;
848
849static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
850{
851 return &self->base;
852}
853
854static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
855{
856 return (if_transform_t *)base;
857}
858
859static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
860 bool *out)
861{
862 bithenge_node_t *cond_node;
863 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
864 if (rc != EOK)
865 return rc;
866 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
867 bithenge_node_dec_ref(cond_node);
868 return EINVAL;
869 }
870 *out = bithenge_boolean_node_value(cond_node);
871 bithenge_node_dec_ref(cond_node);
872 return EOK;
873}
874
875static int if_transform_apply(bithenge_transform_t *base,
876 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
877{
878 if_transform_t *self = transform_as_if(base);
879 bool cond;
880 int rc = if_transform_choose(self, scope, &cond);
881 if (rc != EOK)
882 return rc;
883 return bithenge_transform_apply(
884 cond ? self->true_xform : self->false_xform, scope, in, out);
885}
886
887static int if_transform_prefix_length(bithenge_transform_t *base,
888 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
889{
890 if_transform_t *self = transform_as_if(base);
891 bool cond;
892 int rc = if_transform_choose(self, scope, &cond);
893 if (rc != EOK)
894 return rc;
895 return bithenge_transform_prefix_length(
896 cond ? self->true_xform : self->false_xform, scope, in, out);
897}
898
899static void if_transform_destroy(bithenge_transform_t *base)
900{
901 if_transform_t *self = transform_as_if(base);
902 bithenge_expression_dec_ref(self->expr);
903 bithenge_transform_dec_ref(self->true_xform);
904 bithenge_transform_dec_ref(self->false_xform);
905 free(self);
906}
907
908static const bithenge_transform_ops_t if_transform_ops = {
909 .apply = if_transform_apply,
910 .prefix_length = if_transform_prefix_length,
911 .destroy = if_transform_destroy,
912};
913
914/** Create a transform that applies either of two transforms depending on a
915 * boolean expression. Takes references to @a expr, @a true_xform, and
916 * @a false_xform.
917 * @param[out] out Holds the new transform.
918 * @param expr The boolean expression to evaluate.
919 * @param true_xform The transform to apply if the expression is true.
920 * @param false_xform The transform to apply if the expression is false.
921 * @return EOK on success or an error code from errno.h. */
922int bithenge_if_transform(bithenge_transform_t **out,
923 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
924 bithenge_transform_t *false_xform)
925{
926 int rc;
927 if_transform_t *self = malloc(sizeof(*self));
928 if (!self) {
929 rc = ENOMEM;
930 goto error;
931 }
932
933 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
934 0);
935 if (rc != EOK)
936 goto error;
937
938 self->expr = expr;
939 self->true_xform = true_xform;
940 self->false_xform = false_xform;
941 *out = if_as_transform(self);
942 return EOK;
943
944error:
945 free(self);
946 bithenge_expression_dec_ref(expr);
947 bithenge_transform_dec_ref(true_xform);
948 bithenge_transform_dec_ref(false_xform);
949 return rc;
950}
951
952/** @}
953 */
Note: See TracBrowser for help on using the repository browser.