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

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

Bithenge: add expressions with binary operators

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