source: mainline/uspace/app/bithenge/expression.c@ 2988aec7

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

Bithenge: read FAT files/subdirs; self-recursion and more operators

  • Property mode set to 100644
File size: 25.6 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
[a66ea217]65
66
67/***************** binary_expression *****************/
68
[78d3a00]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 }
[ad5c8a48]100
101 /* Check types and get values. */
[3c70376]102 bithenge_int_t a_int = 0, b_int = 0;
[2988aec7]103 bool a_bool = false, b_bool = false;
[ad5c8a48]104 switch (self->op) {
105 case BITHENGE_EXPRESSION_ADD: /* fallthrough */
106 case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
[0153c87]107 case BITHENGE_EXPRESSION_MULTIPLY: /* fallthrough */
108 case BITHENGE_EXPRESSION_INTEGER_DIVIDE: /* fallthrough */
109 case BITHENGE_EXPRESSION_MODULO: /* fallthrough */
110 case BITHENGE_EXPRESSION_LESS_THAN: /* fallthrough */
111 case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL: /* fallthrough */
112 case BITHENGE_EXPRESSION_GREATER_THAN: /* fallthrough */
113 case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
[ad5c8a48]114 rc = EINVAL;
115 if (bithenge_node_type(a) != BITHENGE_NODE_INTEGER)
116 goto error;
117 if (bithenge_node_type(b) != BITHENGE_NODE_INTEGER)
118 goto error;
119 a_int = bithenge_integer_node_value(a);
120 b_int = bithenge_integer_node_value(b);
121 break;
[2988aec7]122 case BITHENGE_EXPRESSION_AND: /* fallthrough */
123 case BITHENGE_EXPRESSION_OR:
124 rc = EINVAL;
125 if (bithenge_node_type(a) != BITHENGE_NODE_BOOLEAN)
126 goto error;
127 if (bithenge_node_type(b) != BITHENGE_NODE_BOOLEAN)
128 goto error;
129 a_bool = bithenge_boolean_node_value(a);
130 b_bool = bithenge_boolean_node_value(b);
131 break;
132 case BITHENGE_EXPRESSION_CONCAT:
133 if (bithenge_node_type(a) != BITHENGE_NODE_BLOB)
134 goto error;
135 if (bithenge_node_type(b) != BITHENGE_NODE_BLOB)
136 goto error;
137 break;
[ad5c8a48]138 default:
139 break;
140 }
141
[78d3a00]142 switch (self->op) {
[ad5c8a48]143 case BITHENGE_EXPRESSION_ADD:
144 rc = bithenge_new_integer_node(out, a_int + b_int);
145 break;
146 case BITHENGE_EXPRESSION_SUBTRACT:
147 rc = bithenge_new_integer_node(out, a_int - b_int);
148 break;
149 case BITHENGE_EXPRESSION_MULTIPLY:
150 rc = bithenge_new_integer_node(out, a_int * b_int);
151 break;
[0153c87]152 case BITHENGE_EXPRESSION_INTEGER_DIVIDE:
153 /* Integer division can behave in three major ways when the
[2988aec7]154 operands are signed: truncated, floored, or Euclidean. When
[0153c87]155 * b > 0, we give the same result as floored and Euclidean;
156 * otherwise, we currently raise an error. See
157 * https://en.wikipedia.org/wiki/Modulo_operation and its
158 * references. */
159 if (b_int <= 0) {
160 rc = EINVAL;
161 break;
162 }
163 rc = bithenge_new_integer_node(out,
164 (a_int / b_int) + (a_int % b_int < 0 ? -1 : 0));
165 break;
166 case BITHENGE_EXPRESSION_MODULO:
167 /* This is consistent with division; see above. */
168 if (b_int <= 0) {
169 rc = EINVAL;
170 break;
171 }
172 rc = bithenge_new_integer_node(out,
173 (a_int % b_int) + (a_int % b_int < 0 ? b_int : 0));
174 break;
175 case BITHENGE_EXPRESSION_LESS_THAN:
176 rc = bithenge_new_boolean_node(out, a_int < b_int);
177 break;
178 case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL:
179 rc = bithenge_new_boolean_node(out, a_int <= b_int);
180 break;
181 case BITHENGE_EXPRESSION_GREATER_THAN:
182 rc = bithenge_new_boolean_node(out, a_int > b_int);
183 break;
184 case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
185 rc = bithenge_new_boolean_node(out, a_int >= b_int);
186 break;
[78d3a00]187 case BITHENGE_EXPRESSION_EQUALS:
188 rc = bithenge_new_boolean_node(out, bithenge_node_equal(a, b));
189 break;
[0153c87]190 case BITHENGE_EXPRESSION_NOT_EQUALS:
191 rc = bithenge_new_boolean_node(out,
[2988aec7]192 !bithenge_node_equal(a, b));
193 break;
194 case BITHENGE_EXPRESSION_AND:
195 rc = bithenge_new_boolean_node(out, a_bool && b_bool);
196 break;
197 case BITHENGE_EXPRESSION_OR:
198 rc = bithenge_new_boolean_node(out, a_bool || b_bool);
199 break;
200 case BITHENGE_EXPRESSION_MEMBER:
201 rc = bithenge_node_get(a, b, out);
202 b = NULL;
203 break;
204 case BITHENGE_EXPRESSION_CONCAT:
205 rc = bithenge_concat_blob(out, bithenge_node_as_blob(a),
206 bithenge_node_as_blob(b));
207 a = NULL;
208 b = NULL;
[0153c87]209 break;
[ad5c8a48]210 case BITHENGE_EXPRESSION_INVALID_BINARY_OP:
211 assert(false);
212 break;
[78d3a00]213 }
[ad5c8a48]214
215error:
[78d3a00]216 bithenge_node_dec_ref(a);
217 bithenge_node_dec_ref(b);
218 return rc;
219}
220
221static void binary_expression_destroy(bithenge_expression_t *base)
222{
223 binary_expression_t *self = expression_as_binary(base);
224 bithenge_expression_dec_ref(self->a);
225 bithenge_expression_dec_ref(self->b);
226 free(self);
227}
228
229static const bithenge_expression_ops_t binary_expression_ops = {
230 .evaluate = binary_expression_evaluate,
231 .destroy = binary_expression_destroy,
232};
233
234/** Create a binary expression. Takes ownership of @a a and @a b.
235 * @param[out] out Holds the new expression.
236 * @param op The operator to apply.
237 * @param a The first operand.
238 * @param b The second operand.
239 * @return EOK on success or an error code from errno.h. */
240int bithenge_binary_expression(bithenge_expression_t **out,
241 bithenge_binary_op_t op, bithenge_expression_t *a,
242 bithenge_expression_t *b)
243{
244 int rc;
245 binary_expression_t *self = malloc(sizeof(*self));
246 if (!self) {
247 rc = ENOMEM;
248 goto error;
249 }
250
251 rc = bithenge_init_expression(binary_as_expression(self),
252 &binary_expression_ops);
253 if (rc != EOK)
254 goto error;
255
256 self->op = op;
257 self->a = a;
258 self->b = b;
259 *out = binary_as_expression(self);
260 return EOK;
261
262error:
263 bithenge_expression_dec_ref(a);
264 bithenge_expression_dec_ref(b);
265 free(self);
266 return rc;
267}
268
[a66ea217]269
270
271/***************** in_node_expression *****************/
272
273static int in_node_evaluate(bithenge_expression_t *self,
274 bithenge_scope_t *scope, bithenge_node_t **out)
275{
[c9797067]276 for (; scope; scope = bithenge_scope_outer(scope)) {
[a66ea217]277 *out = bithenge_scope_in_node(scope);
278 if (*out)
279 return EOK;
280 }
281 return EINVAL;
282}
283
284static const bithenge_expression_ops_t in_node_ops = {
285 .evaluate = in_node_evaluate,
286 .destroy = expression_indestructible,
287};
288
289static bithenge_expression_t in_node_expression = {
290 &in_node_ops, 1
291};
292
293/** Create an expression that gets the current input node.
294 * @param[out] out Holds the new expression.
295 * @return EOK on success or an error code from errno.h. */
296int bithenge_in_node_expression(bithenge_expression_t **out)
297{
298 bithenge_expression_inc_ref(&in_node_expression);
299 *out = &in_node_expression;
300 return EOK;
301}
302
303
304
305/***************** current_node_expression *****************/
306
[f85ca3f]307static int current_node_evaluate(bithenge_expression_t *self,
308 bithenge_scope_t *scope, bithenge_node_t **out)
309{
310 *out = bithenge_scope_get_current_node(scope);
311 if (!*out)
312 return EINVAL;
313 return EOK;
314}
315
316static const bithenge_expression_ops_t current_node_ops = {
317 .evaluate = current_node_evaluate,
318 .destroy = expression_indestructible,
319};
320
321static bithenge_expression_t current_node_expression = {
322 &current_node_ops, 1
323};
324
325/** Create an expression that gets the current node being created.
326 * @param[out] out Holds the new expression.
327 * @return EOK on success or an error code from errno.h. */
328int bithenge_current_node_expression(bithenge_expression_t **out)
329{
330 bithenge_expression_inc_ref(&current_node_expression);
331 *out = &current_node_expression;
332 return EOK;
333}
334
[a66ea217]335
336
337/***************** param_expression *****************/
338
[6e34bd0]339typedef struct {
340 bithenge_expression_t base;
341 int index;
342} param_expression_t;
343
344static inline param_expression_t *expression_as_param(
345 bithenge_expression_t *base)
346{
347 return (param_expression_t *)base;
348}
349
350static inline bithenge_expression_t *param_as_expression(
351 param_expression_t *self)
352{
353 return &self->base;
354}
355
356static int param_expression_evaluate(bithenge_expression_t *base,
357 bithenge_scope_t *scope, bithenge_node_t **out)
358{
359 param_expression_t *self = expression_as_param(base);
360 return bithenge_scope_get_param(scope, self->index, out);
361}
362
363static void param_expression_destroy(bithenge_expression_t *base)
364{
365 param_expression_t *self = expression_as_param(base);
366 free(self);
367}
368
369static const bithenge_expression_ops_t param_expression_ops = {
370 .evaluate = param_expression_evaluate,
371 .destroy = param_expression_destroy,
372};
373
374/** Create an expression that returns a parameter.
375 * @param[out] out Holds the created expression.
376 * @param index The index of the parameter to get.
377 * @return EOK on success or an error code from errno.h. */
378int bithenge_param_expression(bithenge_expression_t **out, int index)
379{
380 int rc;
381 param_expression_t *self = malloc(sizeof(*self));
382 if (!self)
383 return ENOMEM;
384
385 rc = bithenge_init_expression(param_as_expression(self),
386 &param_expression_ops);
387 if (rc != EOK) {
388 free(self);
389 return rc;
390 }
391
392 self->index = index;
393 *out = param_as_expression(self);
394 return EOK;
395}
396
[a66ea217]397
398
399/***************** const_expression *****************/
400
[6e34bd0]401typedef struct {
402 bithenge_expression_t base;
403 bithenge_node_t *node;
404} const_expression_t;
405
406static inline const_expression_t *expression_as_const(
407 bithenge_expression_t *base)
408{
409 return (const_expression_t *)base;
410}
411
412static inline bithenge_expression_t *const_as_expression(
413 const_expression_t *self)
414{
415 return &self->base;
416}
417
418static int const_expression_evaluate(bithenge_expression_t *base,
419 bithenge_scope_t *scope, bithenge_node_t **out)
420{
421 const_expression_t *self = expression_as_const(base);
422 bithenge_node_inc_ref(self->node);
423 *out = self->node;
424 return EOK;
425}
426
427static void const_expression_destroy(bithenge_expression_t *base)
428{
429 const_expression_t *self = expression_as_const(base);
430 bithenge_node_dec_ref(self->node);
431 free(self);
432}
433
434static const bithenge_expression_ops_t const_expression_ops = {
435 .evaluate = const_expression_evaluate,
436 .destroy = const_expression_destroy,
437};
438
439/** Create an expression that returns a constant. Takes a reference to @a node.
440 * @param[out] out Holds the created expression.
441 * @param node The constant.
442 * @return EOK on success or an error code from errno.h. */
443int bithenge_const_expression(bithenge_expression_t **out,
444 bithenge_node_t *node)
445{
446 int rc;
447 const_expression_t *self = malloc(sizeof(*self));
[3f2ea63]448 if (!self) {
449 rc = ENOMEM;
450 goto error;
451 }
[6e34bd0]452
453 rc = bithenge_init_expression(const_as_expression(self),
454 &const_expression_ops);
[3f2ea63]455 if (rc != EOK)
456 goto error;
[6e34bd0]457
458 self->node = node;
459 *out = const_as_expression(self);
460 return EOK;
[3f2ea63]461
462error:
463 free(self);
464 bithenge_node_dec_ref(node);
465 return rc;
[6e34bd0]466}
467
[c12b2ae]468
469
470/***************** scope_member_expression *****************/
471
472typedef struct {
473 bithenge_expression_t base;
474 bithenge_node_t *key;
475} scope_member_expression_t;
476
477static scope_member_expression_t *expression_as_scope_member(
478 bithenge_expression_t *base)
479{
480 return (scope_member_expression_t *)base;
481}
482
483static bithenge_expression_t *scope_member_as_expression(
484 scope_member_expression_t *expr)
485{
486 return &expr->base;
487}
488
489static int scope_member_expression_evaluate(bithenge_expression_t *base,
490 bithenge_scope_t *scope, bithenge_node_t **out)
491{
492 scope_member_expression_t *self = expression_as_scope_member(base);
493 for (; scope && !bithenge_scope_is_barrier(scope);
494 scope = bithenge_scope_outer(scope)) {
495 bithenge_node_t *cur = bithenge_scope_get_current_node(scope);
[0153c87]496 if (!cur)
497 continue;
498 bithenge_node_inc_ref(self->key);
[c12b2ae]499 int rc = bithenge_node_get(cur, self->key, out);
500 bithenge_node_dec_ref(cur);
501 if (rc != ENOENT) /* EOK or error */
502 return rc;
503 }
[6be4142]504 return bithenge_scope_error(scope, "No scope member %t", self->key);
[c12b2ae]505}
506
507static void scope_member_expression_destroy(bithenge_expression_t *base)
508{
509 scope_member_expression_t *self = expression_as_scope_member(base);
510 bithenge_node_dec_ref(self->key);
511 free(self);
512}
513
514static const bithenge_expression_ops_t scope_member_expression_ops = {
515 .evaluate = scope_member_expression_evaluate,
516 .destroy = scope_member_expression_destroy,
517};
518
519int bithenge_scope_member_expression(bithenge_expression_t **out,
520 bithenge_node_t *key)
521{
522 int rc;
523 scope_member_expression_t *self = malloc(sizeof(*self));
524 if (!self) {
525 rc = ENOMEM;
526 goto error;
527 }
528
529 rc = bithenge_init_expression(scope_member_as_expression(self),
530 &scope_member_expression_ops);
531 if (rc != EOK)
532 goto error;
533
534 self->key = key;
535 *out = scope_member_as_expression(self);
536 return EOK;
537
538error:
539 bithenge_node_dec_ref(key);
540 free(self);
541 return rc;
542}
543
544
545
[0b60d2d]546/***************** subblob_expression *****************/
547
548typedef struct {
549 bithenge_expression_t base;
550 bithenge_expression_t *blob, *start, *limit;
551 bool absolute_limit;
552} subblob_expression_t;
553
554static subblob_expression_t *expression_as_subblob(bithenge_expression_t *base)
555{
556 return (subblob_expression_t *)base;
557}
558
559static bithenge_expression_t *subblob_as_expression(subblob_expression_t *expr)
560{
561 return &expr->base;
562}
563
564static int subblob_expression_evaluate(bithenge_expression_t *base,
565 bithenge_scope_t *scope, bithenge_node_t **out)
566{
567 subblob_expression_t *self = expression_as_subblob(base);
568 bithenge_node_t *start_node;
569 int rc = bithenge_expression_evaluate(self->start, scope, &start_node);
570 if (rc != EOK)
571 return rc;
572 if (bithenge_node_type(start_node) != BITHENGE_NODE_INTEGER) {
573 bithenge_node_dec_ref(start_node);
574 return EINVAL;
575 }
576 bithenge_int_t start = bithenge_integer_node_value(start_node);
577 bithenge_node_dec_ref(start_node);
578
579 bithenge_int_t limit = -1;
580 if (self->limit) {
581 bithenge_node_t *limit_node;
582 rc = bithenge_expression_evaluate(self->limit, scope,
583 &limit_node);
584 if (rc != EOK)
585 return rc;
586 if (bithenge_node_type(limit_node) != BITHENGE_NODE_INTEGER) {
587 bithenge_node_dec_ref(limit_node);
588 return EINVAL;
589 }
590 limit = bithenge_integer_node_value(limit_node);
591 bithenge_node_dec_ref(limit_node);
592 if (self->absolute_limit)
593 limit -= start;
594 }
595
596 if (start < 0 || (self->limit && limit < 0))
597 return EINVAL;
598
599 bithenge_node_t *blob;
600 rc = bithenge_expression_evaluate(self->blob, scope, &blob);
601 if (rc != EOK)
602 return rc;
603 if (bithenge_node_type(blob) != BITHENGE_NODE_BLOB) {
604 bithenge_node_dec_ref(blob);
605 return EINVAL;
606 }
607
608 if (self->limit)
609 return bithenge_new_subblob(out, bithenge_node_as_blob(blob),
610 start, limit);
611 else
612 return bithenge_new_offset_blob(out,
613 bithenge_node_as_blob(blob), start);
614}
615
616static void subblob_expression_destroy(bithenge_expression_t *base)
617{
618 subblob_expression_t *self = expression_as_subblob(base);
[c9797067]619 bithenge_expression_dec_ref(self->blob);
[0b60d2d]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
[c12b2ae]671/***************** param_wrapper *****************/
672
[6e34bd0]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);
[f9c314a5]716 bithenge_scope_t *inner;
[0191bd3]717 int rc = bithenge_scope_new(&inner, outer);
[f9c314a5]718 if (rc != EOK)
719 return rc;
720 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]721 if (rc != EOK)
722 goto error;
723
[f9c314a5]724 rc = bithenge_transform_apply(self->transform, inner, in, out);
[6e34bd0]725 in = NULL;
726
727error:
[f9c314a5]728 bithenge_scope_dec_ref(inner);
[6e34bd0]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);
[f9c314a5]736 bithenge_scope_t *inner;
[0191bd3]737 int rc = bithenge_scope_new(&inner, outer);
[f9c314a5]738 if (rc != EOK)
739 return rc;
740 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]741 if (rc != EOK)
742 goto error;
743
[f9c314a5]744 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
[6e34bd0]745 in = NULL;
746
747error:
[f9c314a5]748 bithenge_scope_dec_ref(inner);
[6e34bd0]749 return rc;
750}
[4056ad0]751
[0191bd3]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
[6e34bd0]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,
[0191bd3]787 .prefix_apply = param_wrapper_prefix_apply,
[6e34bd0]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),
[03cad47]810 &param_wrapper_ops, 0);
[6e34bd0]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
[a66ea217]828
829
830/***************** expression_transform *****************/
831
832/* Also used by inputless_transform. */
[20ac1a4]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);
[a66ea217]854 bithenge_scope_t *inner;
855 int rc = bithenge_scope_new(&inner, scope);
[20ac1a4]856 if (rc != EOK)
857 return rc;
[a66ea217]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);
[20ac1a4]870}
871
[a66ea217]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,
[20ac1a4]912 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
913{
914 *out = 0;
915 return EOK;
916}
917
[a66ea217]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)
[20ac1a4]921{
922 expression_transform_t *self = transform_as_expression(base);
[1b6b76d]923 if (out_size)
924 *out_size = 0;
[a66ea217]925 return bithenge_expression_evaluate(self->expr, scope, out_node);
[20ac1a4]926}
927
[a66ea217]928static const bithenge_transform_ops_t inputless_transform_ops = {
929 .prefix_length = inputless_transform_prefix_length,
930 .prefix_apply = inputless_transform_prefix_apply,
[20ac1a4]931 .destroy = expression_transform_destroy,
932};
933
934/** Create a transform that takes an empty blob and produces the result of an
935 * expression. Takes a reference to the expression.
936 * @param[out] out Holds the new transform.
937 * @param expr The expression to evaluate.
938 * @return EOK on success or an error code from errno.h. */
[a66ea217]939int bithenge_inputless_transform(bithenge_transform_t ** out,
[20ac1a4]940 bithenge_expression_t *expr)
941{
942 int rc;
943 expression_transform_t *self = malloc(sizeof(*self));
944 if (!self) {
945 rc = ENOMEM;
946 goto error;
947 }
948
949 rc = bithenge_init_transform(expression_as_transform(self),
[a66ea217]950 &inputless_transform_ops, 0);
[20ac1a4]951 if (rc != EOK)
952 goto error;
953
954 self->expr = expr;
955 *out = expression_as_transform(self);
956 return EOK;
957
958error:
959 free(self);
960 bithenge_expression_dec_ref(expr);
961 return rc;
962}
963
[6e34bd0]964/** @}
965 */
Note: See TracBrowser for help on using the repository browser.