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

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

Bithenge: search for current node members in outer scopes

  • Property mode set to 100644
File size: 21.1 KB
RevLine 
[6e34bd0]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
[f85ca3f]60static void expression_indestructible(bithenge_expression_t *self)
61{
62 assert(false);
63}
64
[78d3a00]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
[f85ca3f]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
[6e34bd0]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));
[3f2ea63]287 if (!self) {
288 rc = ENOMEM;
289 goto error;
290 }
[6e34bd0]291
292 rc = bithenge_init_expression(const_as_expression(self),
293 &const_expression_ops);
[3f2ea63]294 if (rc != EOK)
295 goto error;
[6e34bd0]296
297 self->node = node;
298 *out = const_as_expression(self);
299 return EOK;
[3f2ea63]300
301error:
302 free(self);
303 bithenge_node_dec_ref(node);
304 return rc;
[6e34bd0]305}
306
[c12b2ae]307
308
309/***************** member_expression *****************/
310
[f85ca3f]311typedef struct {
312 bithenge_expression_t base;
313 bithenge_expression_t *expr;
314 bithenge_node_t *key;
315} member_expression_t;
316
317static member_expression_t *expression_as_member(bithenge_expression_t *base)
318{
319 return (member_expression_t *)base;
320}
321
322static bithenge_expression_t *member_as_expression(member_expression_t *expr)
323{
324 return &expr->base;
325}
326
327static int member_expression_evaluate(bithenge_expression_t *base,
328 bithenge_scope_t *scope, bithenge_node_t **out)
329{
330 member_expression_t *self = expression_as_member(base);
331 bithenge_node_t *node;
332 int rc = bithenge_expression_evaluate(self->expr, scope, &node);
333 if (rc != EOK)
334 return rc;
335 bithenge_node_inc_ref(self->key);
336 rc = bithenge_node_get(node, self->key, out);
337 bithenge_node_dec_ref(node);
338 return rc;
339}
340
341static void member_expression_destroy(bithenge_expression_t *base)
342{
343 member_expression_t *self = expression_as_member(base);
344 bithenge_expression_dec_ref(self->expr);
345 bithenge_node_dec_ref(self->key);
346 free(self);
347}
348
349static const bithenge_expression_ops_t member_expression_ops = {
350 .evaluate = member_expression_evaluate,
351 .destroy = member_expression_destroy,
352};
353
354/** Create an expression that gets a member from a node. Takes references to
355 * @a expr and @a key.
356 * @param[out] out Holds the new expression.
357 * @param expr Calculates the node to get the member of.
358 * @param key The member to get.
359 * @return EOK on success or an error code from errno.h. */
360int bithenge_member_expression(bithenge_expression_t **out,
361 bithenge_expression_t *expr, bithenge_node_t *key)
362{
363 int rc;
364 member_expression_t *self = malloc(sizeof(*self));
365 if (!self) {
366 rc = ENOMEM;
367 goto error;
368 }
369
370 rc = bithenge_init_expression(member_as_expression(self),
371 &member_expression_ops);
372 if (rc != EOK)
373 goto error;
374
375 self->expr = expr;
376 self->key = key;
377 *out = member_as_expression(self);
378 return EOK;
379
380error:
381 bithenge_expression_dec_ref(expr);
382 bithenge_node_dec_ref(key);
383 free(self);
384 return rc;
385}
386
[c12b2ae]387
388
389/***************** scope_member_expression *****************/
390
391typedef struct {
392 bithenge_expression_t base;
393 bithenge_node_t *key;
394} scope_member_expression_t;
395
396static scope_member_expression_t *expression_as_scope_member(
397 bithenge_expression_t *base)
398{
399 return (scope_member_expression_t *)base;
400}
401
402static bithenge_expression_t *scope_member_as_expression(
403 scope_member_expression_t *expr)
404{
405 return &expr->base;
406}
407
408static int scope_member_expression_evaluate(bithenge_expression_t *base,
409 bithenge_scope_t *scope, bithenge_node_t **out)
410{
411 scope_member_expression_t *self = expression_as_scope_member(base);
412 for (; scope && !bithenge_scope_is_barrier(scope);
413 scope = bithenge_scope_outer(scope)) {
414 bithenge_node_inc_ref(self->key);
415 bithenge_node_t *cur = bithenge_scope_get_current_node(scope);
416 int rc = bithenge_node_get(cur, self->key, out);
417 bithenge_node_dec_ref(cur);
418 if (rc != ENOENT) /* EOK or error */
419 return rc;
420 }
421 return ENOENT;
422}
423
424static void scope_member_expression_destroy(bithenge_expression_t *base)
425{
426 scope_member_expression_t *self = expression_as_scope_member(base);
427 bithenge_node_dec_ref(self->key);
428 free(self);
429}
430
431static const bithenge_expression_ops_t scope_member_expression_ops = {
432 .evaluate = scope_member_expression_evaluate,
433 .destroy = scope_member_expression_destroy,
434};
435
436int bithenge_scope_member_expression(bithenge_expression_t **out,
437 bithenge_node_t *key)
438{
439 int rc;
440 scope_member_expression_t *self = malloc(sizeof(*self));
441 if (!self) {
442 rc = ENOMEM;
443 goto error;
444 }
445
446 rc = bithenge_init_expression(scope_member_as_expression(self),
447 &scope_member_expression_ops);
448 if (rc != EOK)
449 goto error;
450
451 self->key = key;
452 *out = scope_member_as_expression(self);
453 return EOK;
454
455error:
456 bithenge_node_dec_ref(key);
457 free(self);
458 return rc;
459}
460
461
462
463/***************** param_wrapper *****************/
464
[6e34bd0]465typedef struct {
466 bithenge_transform_t base;
467 bithenge_transform_t *transform;
468 bithenge_expression_t **params;
469} param_wrapper_t;
470
471static inline bithenge_transform_t *param_wrapper_as_transform(
472 param_wrapper_t *self)
473{
474 return &self->base;
475}
476
477static inline param_wrapper_t *transform_as_param_wrapper(
478 bithenge_transform_t *base)
479{
480 return (param_wrapper_t *)base;
481}
482
483static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
484 *inner, bithenge_scope_t *outer)
485{
486 int rc;
487 int num_params = bithenge_transform_num_params(self->transform);
488 rc = bithenge_scope_alloc_params(inner, num_params);
489 if (rc != EOK)
490 return rc;
491 for (int i = 0; i < num_params; i++) {
492 bithenge_node_t *node;
493 rc = bithenge_expression_evaluate(self->params[i], outer,
494 &node);
495 if (rc != EOK)
496 return rc;
497 rc = bithenge_scope_set_param(inner, i, node);
498 if (rc != EOK)
499 return rc;
500 }
501 return EOK;
502}
503
504static int param_wrapper_apply(bithenge_transform_t *base,
505 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
506{
507 param_wrapper_t *self = transform_as_param_wrapper(base);
[f9c314a5]508 bithenge_scope_t *inner;
[0191bd3]509 int rc = bithenge_scope_new(&inner, outer);
[f9c314a5]510 if (rc != EOK)
511 return rc;
512 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]513 if (rc != EOK)
514 goto error;
515
[f9c314a5]516 rc = bithenge_transform_apply(self->transform, inner, in, out);
[6e34bd0]517 in = NULL;
518
519error:
[f9c314a5]520 bithenge_scope_dec_ref(inner);
[6e34bd0]521 return rc;
522}
523
524static int param_wrapper_prefix_length(bithenge_transform_t *base,
525 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
526{
527 param_wrapper_t *self = transform_as_param_wrapper(base);
[f9c314a5]528 bithenge_scope_t *inner;
[0191bd3]529 int rc = bithenge_scope_new(&inner, outer);
[f9c314a5]530 if (rc != EOK)
531 return rc;
532 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]533 if (rc != EOK)
534 goto error;
535
[f9c314a5]536 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
[6e34bd0]537 in = NULL;
538
539error:
[f9c314a5]540 bithenge_scope_dec_ref(inner);
[6e34bd0]541 return rc;
542}
[4056ad0]543
[0191bd3]544static int param_wrapper_prefix_apply(bithenge_transform_t *base,
545 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
546 aoff64_t *out_length)
547{
548 param_wrapper_t *self = transform_as_param_wrapper(base);
549 bithenge_scope_t *inner;
550 int rc = bithenge_scope_new(&inner, outer);
551 if (rc != EOK)
552 return rc;
553 rc = param_wrapper_fill_scope(self, inner, outer);
554 if (rc != EOK)
555 goto error;
556
557 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
558 out_node, out_length);
559
560error:
561 bithenge_scope_dec_ref(inner);
562 return rc;
563}
564
[6e34bd0]565static void param_wrapper_destroy(bithenge_transform_t *base)
566{
567 param_wrapper_t *self = transform_as_param_wrapper(base);
568 int num_params = bithenge_transform_num_params(self->transform);
569 bithenge_transform_dec_ref(self->transform);
570 for (int i = 0; i < num_params; i++)
571 bithenge_expression_dec_ref(self->params[i]);
572 free(self->params);
573 free(self);
574}
575
576static const bithenge_transform_ops_t param_wrapper_ops = {
577 .apply = param_wrapper_apply,
578 .prefix_length = param_wrapper_prefix_length,
[0191bd3]579 .prefix_apply = param_wrapper_prefix_apply,
[6e34bd0]580 .destroy = param_wrapper_destroy,
581};
582
583/** Create a transform that calculates parameters for another transform. Takes
584 * ownership of @a transform, @a params, and each element of @a params. The
585 * number of parameters must be correct.
586 * @param[out] out Holds the new transform.
587 * @param transform The transform for which parameters are calculated.
588 * @param params The expressions used to calculate the parameters.
589 * @return EOK on success or an error code from errno.h. */
590int bithenge_param_wrapper(bithenge_transform_t **out,
591 bithenge_transform_t *transform, bithenge_expression_t **params)
592{
593 int rc;
594 int num_params = bithenge_transform_num_params(transform);
595 param_wrapper_t *self = malloc(sizeof(*self));
596 if (!self) {
597 rc = ENOMEM;
598 goto error;
599 }
600
601 rc = bithenge_init_transform(param_wrapper_as_transform(self),
[03cad47]602 &param_wrapper_ops, 0);
[6e34bd0]603 if (rc != EOK)
604 goto error;
605
606 self->transform = transform;
607 self->params = params;
608 *out = param_wrapper_as_transform(self);
609 return EOK;
610
611error:
612 free(self);
613 for (int i = 0; i < num_params; i++)
614 bithenge_expression_dec_ref(params[i]);
615 free(params);
616 bithenge_transform_dec_ref(transform);
617 return rc;
618}
619
[20ac1a4]620typedef struct {
621 bithenge_transform_t base;
622 bithenge_expression_t *expr;
623} expression_transform_t;
624
625static inline bithenge_transform_t *expression_as_transform(
626 expression_transform_t *self)
627{
628 return &self->base;
629}
630
631static inline expression_transform_t *transform_as_expression(
632 bithenge_transform_t *base)
633{
634 return (expression_transform_t *)base;
635}
636
637static int expression_transform_apply(bithenge_transform_t *base,
638 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
639{
640 expression_transform_t *self = transform_as_expression(base);
641 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
642 return EINVAL;
643 aoff64_t len;
644 int rc = bithenge_blob_size(bithenge_node_as_blob(in), &len);
645 if (rc != EOK)
646 return rc;
647 if (len != 0)
648 return EINVAL;
649 return bithenge_expression_evaluate(self->expr, scope, out);
650}
651
652static int expression_transform_prefix_length(bithenge_transform_t *base,
653 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
654{
655 *out = 0;
656 return EOK;
657}
658
659static void expression_transform_destroy(bithenge_transform_t *base)
660{
661 expression_transform_t *self = transform_as_expression(base);
662 bithenge_expression_dec_ref(self->expr);
663 free(self);
664}
665
666static const bithenge_transform_ops_t expression_transform_ops = {
667 .apply = expression_transform_apply,
668 .prefix_length = expression_transform_prefix_length,
669 .destroy = expression_transform_destroy,
670};
671
672/** Create a transform that takes an empty blob and produces the result of an
673 * expression. Takes a reference to the expression.
674 * @param[out] out Holds the new transform.
675 * @param expr The expression to evaluate.
676 * @return EOK on success or an error code from errno.h. */
677int bithenge_expression_transform(bithenge_transform_t ** out,
678 bithenge_expression_t *expr)
679{
680 int rc;
681 expression_transform_t *self = malloc(sizeof(*self));
682 if (!self) {
683 rc = ENOMEM;
684 goto error;
685 }
686
687 rc = bithenge_init_transform(expression_as_transform(self),
688 &expression_transform_ops, 0);
689 if (rc != EOK)
690 goto error;
691
692 self->expr = expr;
693 *out = expression_as_transform(self);
694 return EOK;
695
696error:
697 free(self);
698 bithenge_expression_dec_ref(expr);
699 return rc;
700}
701
[10334c2e]702typedef struct {
703 bithenge_transform_t base;
704 bithenge_expression_t *expr;
705 bithenge_transform_t *true_xform, *false_xform;
706} if_transform_t;
707
708static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
709{
710 return &self->base;
711}
712
713static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
714{
715 return (if_transform_t *)base;
716}
717
718static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
719 bool *out)
720{
721 bithenge_node_t *cond_node;
722 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
723 if (rc != EOK)
724 return rc;
725 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
726 bithenge_node_dec_ref(cond_node);
727 return EINVAL;
728 }
729 *out = bithenge_boolean_node_value(cond_node);
730 bithenge_node_dec_ref(cond_node);
731 return EOK;
732}
733
734static int if_transform_apply(bithenge_transform_t *base,
735 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
736{
737 if_transform_t *self = transform_as_if(base);
738 bool cond;
739 int rc = if_transform_choose(self, scope, &cond);
740 if (rc != EOK)
741 return rc;
742 return bithenge_transform_apply(
743 cond ? self->true_xform : self->false_xform, scope, in, out);
744}
745
746static int if_transform_prefix_length(bithenge_transform_t *base,
747 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
748{
749 if_transform_t *self = transform_as_if(base);
750 bool cond;
751 int rc = if_transform_choose(self, scope, &cond);
752 if (rc != EOK)
753 return rc;
754 return bithenge_transform_prefix_length(
755 cond ? self->true_xform : self->false_xform, scope, in, out);
756}
757
758static void if_transform_destroy(bithenge_transform_t *base)
759{
760 if_transform_t *self = transform_as_if(base);
761 bithenge_expression_dec_ref(self->expr);
762 bithenge_transform_dec_ref(self->true_xform);
763 bithenge_transform_dec_ref(self->false_xform);
764 free(self);
765}
766
767static const bithenge_transform_ops_t if_transform_ops = {
768 .apply = if_transform_apply,
769 .prefix_length = if_transform_prefix_length,
770 .destroy = if_transform_destroy,
771};
772
773/** Create a transform that applies either of two transforms depending on a
774 * boolean expression. Takes references to @a expr, @a true_xform, and
775 * @a false_xform.
776 * @param[out] out Holds the new transform.
777 * @param expr The boolean expression to evaluate.
778 * @param true_xform The transform to apply if the expression is true.
[b8d45e9e]779 * @param false_xform The transform to apply if the expression is false.
780 * @return EOK on success or an error code from errno.h. */
[10334c2e]781int bithenge_if_transform(bithenge_transform_t **out,
782 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
783 bithenge_transform_t *false_xform)
784{
785 int rc;
786 if_transform_t *self = malloc(sizeof(*self));
787 if (!self) {
788 rc = ENOMEM;
789 goto error;
790 }
791
792 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
793 0);
794 if (rc != EOK)
795 goto error;
796
797 self->expr = expr;
798 self->true_xform = true_xform;
799 self->false_xform = false_xform;
800 *out = if_as_transform(self);
801 return EOK;
802
803error:
804 free(self);
805 bithenge_expression_dec_ref(expr);
806 bithenge_transform_dec_ref(true_xform);
807 bithenge_transform_dec_ref(false_xform);
808 return rc;
809}
810
[6e34bd0]811/** @}
812 */
Note: See TracBrowser for help on using the repository browser.