source: mainline/uspace/app/bithenge/expression.c@ 71450c8

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

Bithenge: move compound transforms to separate file; fix warnings

  • Property mode set to 100644
File size: 25.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
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 = 0, b_int = 0;
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/***************** subblob_expression *****************/
548
549typedef struct {
550 bithenge_expression_t base;
551 bithenge_expression_t *blob, *start, *limit;
552 bool absolute_limit;
553} subblob_expression_t;
554
555static subblob_expression_t *expression_as_subblob(bithenge_expression_t *base)
556{
557 return (subblob_expression_t *)base;
558}
559
560static bithenge_expression_t *subblob_as_expression(subblob_expression_t *expr)
561{
562 return &expr->base;
563}
564
565static int subblob_expression_evaluate(bithenge_expression_t *base,
566 bithenge_scope_t *scope, bithenge_node_t **out)
567{
568 subblob_expression_t *self = expression_as_subblob(base);
569 bithenge_node_t *start_node;
570 int rc = bithenge_expression_evaluate(self->start, scope, &start_node);
571 if (rc != EOK)
572 return rc;
573 if (bithenge_node_type(start_node) != BITHENGE_NODE_INTEGER) {
574 bithenge_node_dec_ref(start_node);
575 return EINVAL;
576 }
577 bithenge_int_t start = bithenge_integer_node_value(start_node);
578 bithenge_node_dec_ref(start_node);
579
580 bithenge_int_t limit = -1;
581 if (self->limit) {
582 bithenge_node_t *limit_node;
583 rc = bithenge_expression_evaluate(self->limit, scope,
584 &limit_node);
585 if (rc != EOK)
586 return rc;
587 if (bithenge_node_type(limit_node) != BITHENGE_NODE_INTEGER) {
588 bithenge_node_dec_ref(limit_node);
589 return EINVAL;
590 }
591 limit = bithenge_integer_node_value(limit_node);
592 bithenge_node_dec_ref(limit_node);
593 if (self->absolute_limit)
594 limit -= start;
595 }
596
597 if (start < 0 || (self->limit && limit < 0))
598 return EINVAL;
599
600 bithenge_node_t *blob;
601 rc = bithenge_expression_evaluate(self->blob, scope, &blob);
602 if (rc != EOK)
603 return rc;
604 if (bithenge_node_type(blob) != BITHENGE_NODE_BLOB) {
605 bithenge_node_dec_ref(blob);
606 return EINVAL;
607 }
608
609 if (self->limit)
610 return bithenge_new_subblob(out, bithenge_node_as_blob(blob),
611 start, limit);
612 else
613 return bithenge_new_offset_blob(out,
614 bithenge_node_as_blob(blob), start);
615}
616
617static void subblob_expression_destroy(bithenge_expression_t *base)
618{
619 subblob_expression_t *self = expression_as_subblob(base);
620 bithenge_expression_dec_ref(self->start);
621 bithenge_expression_dec_ref(self->limit);
622 free(self);
623}
624
625static const bithenge_expression_ops_t subblob_expression_ops = {
626 .evaluate = subblob_expression_evaluate,
627 .destroy = subblob_expression_destroy,
628};
629
630/** Create an expression that gets a subblob. Takes references to @a blob,
631 * @a start, and @a limit.
632 * @param[out] out Holds the new expression.
633 * @param blob Calculates the blob.
634 * @param start Calculates the start offset within the blob.
635 * @param limit Calculates the limit. Can be NULL, in which case an offset blob
636 * is returned.
637 * @param absolute_limit If true, the limit is an absolute offset; otherwise,
638 * it is relative to the start.
639 * @return EOK on success or an error code from errno.h. */
640int bithenge_subblob_expression(bithenge_expression_t **out,
641 bithenge_expression_t *blob, bithenge_expression_t *start,
642 bithenge_expression_t *limit, bool absolute_limit)
643{
644 int rc;
645 subblob_expression_t *self = malloc(sizeof(*self));
646 if (!self) {
647 rc = ENOMEM;
648 goto error;
649 }
650
651 rc = bithenge_init_expression(subblob_as_expression(self),
652 &subblob_expression_ops);
653 if (rc != EOK)
654 goto error;
655
656 self->blob = blob;
657 self->start = start;
658 self->limit = limit;
659 self->absolute_limit = absolute_limit;
660 *out = subblob_as_expression(self);
661 return EOK;
662
663error:
664 bithenge_expression_dec_ref(blob);
665 bithenge_expression_dec_ref(start);
666 bithenge_expression_dec_ref(limit);
667 free(self);
668 return rc;
669}
670
671/***************** param_wrapper *****************/
672
673typedef struct {
674 bithenge_transform_t base;
675 bithenge_transform_t *transform;
676 bithenge_expression_t **params;
677} param_wrapper_t;
678
679static inline bithenge_transform_t *param_wrapper_as_transform(
680 param_wrapper_t *self)
681{
682 return &self->base;
683}
684
685static inline param_wrapper_t *transform_as_param_wrapper(
686 bithenge_transform_t *base)
687{
688 return (param_wrapper_t *)base;
689}
690
691static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
692 *inner, bithenge_scope_t *outer)
693{
694 int rc;
695 int num_params = bithenge_transform_num_params(self->transform);
696 rc = bithenge_scope_alloc_params(inner, num_params);
697 if (rc != EOK)
698 return rc;
699 for (int i = 0; i < num_params; i++) {
700 bithenge_node_t *node;
701 rc = bithenge_expression_evaluate(self->params[i], outer,
702 &node);
703 if (rc != EOK)
704 return rc;
705 rc = bithenge_scope_set_param(inner, i, node);
706 if (rc != EOK)
707 return rc;
708 }
709 return EOK;
710}
711
712static int param_wrapper_apply(bithenge_transform_t *base,
713 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
714{
715 param_wrapper_t *self = transform_as_param_wrapper(base);
716 bithenge_scope_t *inner;
717 int rc = bithenge_scope_new(&inner, outer);
718 if (rc != EOK)
719 return rc;
720 rc = param_wrapper_fill_scope(self, inner, outer);
721 if (rc != EOK)
722 goto error;
723
724 rc = bithenge_transform_apply(self->transform, inner, in, out);
725 in = NULL;
726
727error:
728 bithenge_scope_dec_ref(inner);
729 return rc;
730}
731
732static int param_wrapper_prefix_length(bithenge_transform_t *base,
733 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
734{
735 param_wrapper_t *self = transform_as_param_wrapper(base);
736 bithenge_scope_t *inner;
737 int rc = bithenge_scope_new(&inner, outer);
738 if (rc != EOK)
739 return rc;
740 rc = param_wrapper_fill_scope(self, inner, outer);
741 if (rc != EOK)
742 goto error;
743
744 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
745 in = NULL;
746
747error:
748 bithenge_scope_dec_ref(inner);
749 return rc;
750}
751
752static int param_wrapper_prefix_apply(bithenge_transform_t *base,
753 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
754 aoff64_t *out_length)
755{
756 param_wrapper_t *self = transform_as_param_wrapper(base);
757 bithenge_scope_t *inner;
758 int rc = bithenge_scope_new(&inner, outer);
759 if (rc != EOK)
760 return rc;
761 rc = param_wrapper_fill_scope(self, inner, outer);
762 if (rc != EOK)
763 goto error;
764
765 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
766 out_node, out_length);
767
768error:
769 bithenge_scope_dec_ref(inner);
770 return rc;
771}
772
773static void param_wrapper_destroy(bithenge_transform_t *base)
774{
775 param_wrapper_t *self = transform_as_param_wrapper(base);
776 int num_params = bithenge_transform_num_params(self->transform);
777 bithenge_transform_dec_ref(self->transform);
778 for (int i = 0; i < num_params; i++)
779 bithenge_expression_dec_ref(self->params[i]);
780 free(self->params);
781 free(self);
782}
783
784static const bithenge_transform_ops_t param_wrapper_ops = {
785 .apply = param_wrapper_apply,
786 .prefix_length = param_wrapper_prefix_length,
787 .prefix_apply = param_wrapper_prefix_apply,
788 .destroy = param_wrapper_destroy,
789};
790
791/** Create a transform that calculates parameters for another transform. Takes
792 * ownership of @a transform, @a params, and each element of @a params. The
793 * number of parameters must be correct.
794 * @param[out] out Holds the new transform.
795 * @param transform The transform for which parameters are calculated.
796 * @param params The expressions used to calculate the parameters.
797 * @return EOK on success or an error code from errno.h. */
798int bithenge_param_wrapper(bithenge_transform_t **out,
799 bithenge_transform_t *transform, bithenge_expression_t **params)
800{
801 int rc;
802 int num_params = bithenge_transform_num_params(transform);
803 param_wrapper_t *self = malloc(sizeof(*self));
804 if (!self) {
805 rc = ENOMEM;
806 goto error;
807 }
808
809 rc = bithenge_init_transform(param_wrapper_as_transform(self),
810 &param_wrapper_ops, 0);
811 if (rc != EOK)
812 goto error;
813
814 self->transform = transform;
815 self->params = params;
816 *out = param_wrapper_as_transform(self);
817 return EOK;
818
819error:
820 free(self);
821 for (int i = 0; i < num_params; i++)
822 bithenge_expression_dec_ref(params[i]);
823 free(params);
824 bithenge_transform_dec_ref(transform);
825 return rc;
826}
827
828
829
830/***************** expression_transform *****************/
831
832/* Also used by inputless_transform. */
833typedef struct {
834 bithenge_transform_t base;
835 bithenge_expression_t *expr;
836} expression_transform_t;
837
838static inline bithenge_transform_t *expression_as_transform(
839 expression_transform_t *self)
840{
841 return &self->base;
842}
843
844static inline expression_transform_t *transform_as_expression(
845 bithenge_transform_t *base)
846{
847 return (expression_transform_t *)base;
848}
849
850static int expression_transform_apply(bithenge_transform_t *base,
851 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
852{
853 expression_transform_t *self = transform_as_expression(base);
854 bithenge_scope_t *inner;
855 int rc = bithenge_scope_new(&inner, scope);
856 if (rc != EOK)
857 return rc;
858 bithenge_scope_set_in_node(inner, in);
859 rc = bithenge_expression_evaluate(self->expr, inner, out);
860 bithenge_scope_dec_ref(inner);
861 return rc;
862}
863
864/* Also used by inputless_transform. */
865static void expression_transform_destroy(bithenge_transform_t *base)
866{
867 expression_transform_t *self = transform_as_expression(base);
868 bithenge_expression_dec_ref(self->expr);
869 free(self);
870}
871
872static const bithenge_transform_ops_t expression_transform_ops = {
873 .apply = expression_transform_apply,
874 .destroy = expression_transform_destroy,
875};
876
877/** Create a transform that evaluates an expression on the input node. Takes a
878 * reference to the expression.
879 * @param[out] out Holds the new transform.
880 * @param expr The expression to evaluate.
881 * @return EOK on success or an error code from errno.h. */
882int bithenge_expression_transform(bithenge_transform_t ** out,
883 bithenge_expression_t *expr)
884{
885 int rc;
886 expression_transform_t *self = malloc(sizeof(*self));
887 if (!self) {
888 rc = ENOMEM;
889 goto error;
890 }
891
892 rc = bithenge_init_transform(expression_as_transform(self),
893 &expression_transform_ops, 0);
894 if (rc != EOK)
895 goto error;
896
897 self->expr = expr;
898 *out = expression_as_transform(self);
899 return EOK;
900
901error:
902 free(self);
903 bithenge_expression_dec_ref(expr);
904 return rc;
905}
906
907
908
909/***************** inputless_transform *****************/
910
911static int inputless_transform_prefix_length(bithenge_transform_t *base,
912 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
913{
914 *out = 0;
915 return EOK;
916}
917
918static int inputless_transform_prefix_apply(bithenge_transform_t *base,
919 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
920 aoff64_t *out_size)
921{
922 expression_transform_t *self = transform_as_expression(base);
923 *out_size = 0;
924 return bithenge_expression_evaluate(self->expr, scope, out_node);
925}
926
927static const bithenge_transform_ops_t inputless_transform_ops = {
928 .prefix_length = inputless_transform_prefix_length,
929 .prefix_apply = inputless_transform_prefix_apply,
930 .destroy = expression_transform_destroy,
931};
932
933/** Create a transform that takes an empty blob and produces the result of an
934 * expression. Takes a reference to the expression.
935 * @param[out] out Holds the new transform.
936 * @param expr The expression to evaluate.
937 * @return EOK on success or an error code from errno.h. */
938int bithenge_inputless_transform(bithenge_transform_t ** out,
939 bithenge_expression_t *expr)
940{
941 int rc;
942 expression_transform_t *self = malloc(sizeof(*self));
943 if (!self) {
944 rc = ENOMEM;
945 goto error;
946 }
947
948 rc = bithenge_init_transform(expression_as_transform(self),
949 &inputless_transform_ops, 0);
950 if (rc != EOK)
951 goto error;
952
953 self->expr = expr;
954 *out = expression_as_transform(self);
955 return EOK;
956
957error:
958 free(self);
959 bithenge_expression_dec_ref(expr);
960 return rc;
961}
962
963/** @}
964 */
Note: See TracBrowser for help on using the repository browser.