source: mainline/uspace/app/bithenge/expression.c@ 6be4142

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

Bithenge: print transform errors; fixes and fat.bh improvements

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