source: mainline/uspace/lib/bithenge/expression.c@ 1a3b953

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

Bithenge: better error injection

  • Property mode set to 100644
File size: 31.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 "os.h"
43#include "transform.h"
44#include "tree.h"
45
46/** Initialize a new expression.
47 * @param[out] self Expression to initialize.
48 * @param[in] ops Operations provided by the expression.
49 * @return EOK or an error code from errno.h. */
50int bithenge_init_expression(bithenge_expression_t *self,
51 const bithenge_expression_ops_t *ops)
52{
53 assert(ops);
54 assert(ops->evaluate);
55 assert(ops->destroy);
56 if (bithenge_should_fail())
57 return ENOMEM;
58 self->ops = ops;
59 self->refs = 1;
60 return EOK;
61}
62
63static void expression_indestructible(bithenge_expression_t *self)
64{
65 assert(false);
66}
67
68
69
70/***************** binary_expression *****************/
71
72typedef struct {
73 bithenge_expression_t base;
74 bithenge_binary_op_t op;
75 bithenge_expression_t *a, *b;
76} binary_expression_t;
77
78static inline binary_expression_t *expression_as_binary(
79 bithenge_expression_t *base)
80{
81 return (binary_expression_t *)base;
82}
83
84static inline bithenge_expression_t *binary_as_expression(
85 binary_expression_t *self)
86{
87 return &self->base;
88}
89
90static int binary_expression_evaluate(bithenge_expression_t *base,
91 bithenge_scope_t *scope, bithenge_node_t **out)
92{
93 int rc;
94 binary_expression_t *self = expression_as_binary(base);
95 bithenge_node_t *a, *b;
96 rc = bithenge_expression_evaluate(self->a, scope, &a);
97 if (rc != EOK)
98 return rc;
99 if (self->op != BITHENGE_EXPRESSION_CONCAT) {
100 rc = bithenge_expression_evaluate(self->b, scope, &b);
101 if (rc != EOK) {
102 bithenge_node_dec_ref(a);
103 return rc;
104 }
105 }
106
107 /* Check types and get values. */
108 bithenge_int_t a_int = 0, b_int = 0;
109 bool a_bool = false, b_bool = false, out_bool = false;
110 switch (self->op) {
111 case BITHENGE_EXPRESSION_ADD: /* fallthrough */
112 case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
113 case BITHENGE_EXPRESSION_MULTIPLY: /* fallthrough */
114 case BITHENGE_EXPRESSION_INTEGER_DIVIDE: /* fallthrough */
115 case BITHENGE_EXPRESSION_MODULO: /* fallthrough */
116 case BITHENGE_EXPRESSION_LESS_THAN: /* fallthrough */
117 case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL: /* fallthrough */
118 case BITHENGE_EXPRESSION_GREATER_THAN: /* fallthrough */
119 case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
120 rc = EINVAL;
121 if (bithenge_node_type(a) != BITHENGE_NODE_INTEGER)
122 goto error;
123 if (bithenge_node_type(b) != BITHENGE_NODE_INTEGER)
124 goto error;
125 a_int = bithenge_integer_node_value(a);
126 b_int = bithenge_integer_node_value(b);
127 break;
128 case BITHENGE_EXPRESSION_AND: /* fallthrough */
129 case BITHENGE_EXPRESSION_OR:
130 rc = EINVAL;
131 if (bithenge_node_type(a) != BITHENGE_NODE_BOOLEAN)
132 goto error;
133 if (bithenge_node_type(b) != BITHENGE_NODE_BOOLEAN)
134 goto error;
135 a_bool = bithenge_boolean_node_value(a);
136 b_bool = bithenge_boolean_node_value(b);
137 break;
138 case BITHENGE_EXPRESSION_CONCAT:
139 if (bithenge_node_type(a) != BITHENGE_NODE_BLOB)
140 goto error;
141 break;
142 default:
143 break;
144 }
145
146 switch (self->op) {
147 case BITHENGE_EXPRESSION_ADD:
148 rc = bithenge_new_integer_node(out, a_int + b_int);
149 break;
150 case BITHENGE_EXPRESSION_SUBTRACT:
151 rc = bithenge_new_integer_node(out, a_int - b_int);
152 break;
153 case BITHENGE_EXPRESSION_MULTIPLY:
154 rc = bithenge_new_integer_node(out, a_int * b_int);
155 break;
156 case BITHENGE_EXPRESSION_INTEGER_DIVIDE:
157 /* Integer division can behave in three major ways when the
158 operands are signed: truncated, floored, or Euclidean. When
159 * b > 0, we give the same result as floored and Euclidean;
160 * otherwise, we currently raise an error. See
161 * https://en.wikipedia.org/wiki/Modulo_operation and its
162 * references. */
163 if (b_int <= 0) {
164 rc = EINVAL;
165 break;
166 }
167 rc = bithenge_new_integer_node(out,
168 (a_int / b_int) + (a_int % b_int < 0 ? -1 : 0));
169 break;
170 case BITHENGE_EXPRESSION_MODULO:
171 /* This is consistent with division; see above. */
172 if (b_int <= 0) {
173 rc = EINVAL;
174 break;
175 }
176 rc = bithenge_new_integer_node(out,
177 (a_int % b_int) + (a_int % b_int < 0 ? b_int : 0));
178 break;
179 case BITHENGE_EXPRESSION_LESS_THAN:
180 rc = bithenge_new_boolean_node(out, a_int < b_int);
181 break;
182 case BITHENGE_EXPRESSION_LESS_THAN_OR_EQUAL:
183 rc = bithenge_new_boolean_node(out, a_int <= b_int);
184 break;
185 case BITHENGE_EXPRESSION_GREATER_THAN:
186 rc = bithenge_new_boolean_node(out, a_int > b_int);
187 break;
188 case BITHENGE_EXPRESSION_GREATER_THAN_OR_EQUAL:
189 rc = bithenge_new_boolean_node(out, a_int >= b_int);
190 break;
191 case BITHENGE_EXPRESSION_EQUALS:
192 rc = bithenge_node_equal(&out_bool, a, b);
193 if (rc != EOK)
194 break;
195 rc = bithenge_new_boolean_node(out, out_bool);
196 break;
197 case BITHENGE_EXPRESSION_NOT_EQUALS:
198 rc = bithenge_node_equal(&out_bool, a, b);
199 if (rc != EOK)
200 break;
201 rc = bithenge_new_boolean_node(out, !out_bool);
202 break;
203 case BITHENGE_EXPRESSION_AND:
204 rc = bithenge_new_boolean_node(out, a_bool && b_bool);
205 break;
206 case BITHENGE_EXPRESSION_OR:
207 rc = bithenge_new_boolean_node(out, a_bool || b_bool);
208 break;
209 case BITHENGE_EXPRESSION_MEMBER:
210 rc = bithenge_node_get(a, b, out);
211 b = NULL;
212 break;
213 case BITHENGE_EXPRESSION_CONCAT:
214 bithenge_expression_inc_ref(self->b);
215 bithenge_scope_inc_ref(scope);
216 rc = bithenge_concat_blob_lazy(out, bithenge_node_as_blob(a),
217 self->b, scope);
218 a = NULL;
219 b = NULL;
220 break;
221 case BITHENGE_EXPRESSION_INVALID_BINARY_OP:
222 assert(false);
223 break;
224 }
225
226error:
227 bithenge_node_dec_ref(a);
228 bithenge_node_dec_ref(b);
229 return rc;
230}
231
232static void binary_expression_destroy(bithenge_expression_t *base)
233{
234 binary_expression_t *self = expression_as_binary(base);
235 bithenge_expression_dec_ref(self->a);
236 bithenge_expression_dec_ref(self->b);
237 free(self);
238}
239
240static const bithenge_expression_ops_t binary_expression_ops = {
241 .evaluate = binary_expression_evaluate,
242 .destroy = binary_expression_destroy,
243};
244
245/** Create a binary expression. Takes ownership of @a a and @a b.
246 * @param[out] out Holds the new expression.
247 * @param op The operator to apply.
248 * @param a The first operand.
249 * @param b The second operand.
250 * @return EOK on success or an error code from errno.h. */
251int bithenge_binary_expression(bithenge_expression_t **out,
252 bithenge_binary_op_t op, bithenge_expression_t *a,
253 bithenge_expression_t *b)
254{
255 int rc;
256 binary_expression_t *self = malloc(sizeof(*self));
257 if (!self) {
258 rc = ENOMEM;
259 goto error;
260 }
261
262 rc = bithenge_init_expression(binary_as_expression(self),
263 &binary_expression_ops);
264 if (rc != EOK)
265 goto error;
266
267 self->op = op;
268 self->a = a;
269 self->b = b;
270 *out = binary_as_expression(self);
271 return EOK;
272
273error:
274 bithenge_expression_dec_ref(a);
275 bithenge_expression_dec_ref(b);
276 free(self);
277 return rc;
278}
279
280
281
282/***************** in_node_expression *****************/
283
284static int in_node_evaluate(bithenge_expression_t *self,
285 bithenge_scope_t *scope, bithenge_node_t **out)
286{
287 for (; scope; scope = bithenge_scope_outer(scope)) {
288 *out = bithenge_scope_in_node(scope);
289 if (*out)
290 return EOK;
291 }
292 return EINVAL;
293}
294
295static const bithenge_expression_ops_t in_node_ops = {
296 .evaluate = in_node_evaluate,
297 .destroy = expression_indestructible,
298};
299
300static bithenge_expression_t in_node_expression = {
301 &in_node_ops, 1
302};
303
304/** Create an expression that gets the current input node.
305 * @param[out] out Holds the new expression.
306 * @return EOK on success or an error code from errno.h. */
307int bithenge_in_node_expression(bithenge_expression_t **out)
308{
309 if (bithenge_should_fail())
310 return ENOMEM;
311 bithenge_expression_inc_ref(&in_node_expression);
312 *out = &in_node_expression;
313 return EOK;
314}
315
316
317
318/***************** current_node_expression *****************/
319
320static int current_node_evaluate(bithenge_expression_t *self,
321 bithenge_scope_t *scope, bithenge_node_t **out)
322{
323 *out = bithenge_scope_get_current_node(scope);
324 if (!*out)
325 return EINVAL;
326 return EOK;
327}
328
329static const bithenge_expression_ops_t current_node_ops = {
330 .evaluate = current_node_evaluate,
331 .destroy = expression_indestructible,
332};
333
334static bithenge_expression_t current_node_expression = {
335 &current_node_ops, 1
336};
337
338/** Create an expression that gets the current node being created.
339 * @param[out] out Holds the new expression.
340 * @return EOK on success or an error code from errno.h. */
341int bithenge_current_node_expression(bithenge_expression_t **out)
342{
343 bithenge_expression_inc_ref(&current_node_expression);
344 *out = &current_node_expression;
345 return EOK;
346}
347
348
349
350/***************** param_expression *****************/
351
352typedef struct {
353 bithenge_expression_t base;
354 int index;
355} param_expression_t;
356
357static inline param_expression_t *expression_as_param(
358 bithenge_expression_t *base)
359{
360 return (param_expression_t *)base;
361}
362
363static inline bithenge_expression_t *param_as_expression(
364 param_expression_t *self)
365{
366 return &self->base;
367}
368
369static int param_expression_evaluate(bithenge_expression_t *base,
370 bithenge_scope_t *scope, bithenge_node_t **out)
371{
372 param_expression_t *self = expression_as_param(base);
373 return bithenge_scope_get_param(scope, self->index, out);
374}
375
376static void param_expression_destroy(bithenge_expression_t *base)
377{
378 param_expression_t *self = expression_as_param(base);
379 free(self);
380}
381
382static const bithenge_expression_ops_t param_expression_ops = {
383 .evaluate = param_expression_evaluate,
384 .destroy = param_expression_destroy,
385};
386
387/** Create an expression that returns a parameter.
388 * @param[out] out Holds the created expression.
389 * @param index The index of the parameter to get.
390 * @return EOK on success or an error code from errno.h. */
391int bithenge_param_expression(bithenge_expression_t **out, int index)
392{
393 int rc;
394 param_expression_t *self = malloc(sizeof(*self));
395 if (!self)
396 return ENOMEM;
397
398 rc = bithenge_init_expression(param_as_expression(self),
399 &param_expression_ops);
400 if (rc != EOK) {
401 free(self);
402 return rc;
403 }
404
405 self->index = index;
406 *out = param_as_expression(self);
407 return EOK;
408}
409
410
411
412/***************** const_expression *****************/
413
414typedef struct {
415 bithenge_expression_t base;
416 bithenge_node_t *node;
417} const_expression_t;
418
419static inline const_expression_t *expression_as_const(
420 bithenge_expression_t *base)
421{
422 return (const_expression_t *)base;
423}
424
425static inline bithenge_expression_t *const_as_expression(
426 const_expression_t *self)
427{
428 return &self->base;
429}
430
431static int const_expression_evaluate(bithenge_expression_t *base,
432 bithenge_scope_t *scope, bithenge_node_t **out)
433{
434 const_expression_t *self = expression_as_const(base);
435 bithenge_node_inc_ref(self->node);
436 *out = self->node;
437 return EOK;
438}
439
440static void const_expression_destroy(bithenge_expression_t *base)
441{
442 const_expression_t *self = expression_as_const(base);
443 bithenge_node_dec_ref(self->node);
444 free(self);
445}
446
447static const bithenge_expression_ops_t const_expression_ops = {
448 .evaluate = const_expression_evaluate,
449 .destroy = const_expression_destroy,
450};
451
452/** Create an expression that returns a constant. Takes a reference to @a node.
453 * @param[out] out Holds the created expression.
454 * @param node The constant.
455 * @return EOK on success or an error code from errno.h. */
456int bithenge_const_expression(bithenge_expression_t **out,
457 bithenge_node_t *node)
458{
459 int rc;
460 const_expression_t *self = malloc(sizeof(*self));
461 if (!self) {
462 rc = ENOMEM;
463 goto error;
464 }
465
466 rc = bithenge_init_expression(const_as_expression(self),
467 &const_expression_ops);
468 if (rc != EOK)
469 goto error;
470
471 self->node = node;
472 *out = const_as_expression(self);
473 return EOK;
474
475error:
476 free(self);
477 bithenge_node_dec_ref(node);
478 return rc;
479}
480
481
482
483/***************** scope_member_expression *****************/
484
485typedef struct {
486 bithenge_expression_t base;
487 bithenge_node_t *key;
488} scope_member_expression_t;
489
490static scope_member_expression_t *expression_as_scope_member(
491 bithenge_expression_t *base)
492{
493 return (scope_member_expression_t *)base;
494}
495
496static bithenge_expression_t *scope_member_as_expression(
497 scope_member_expression_t *expr)
498{
499 return &expr->base;
500}
501
502static int scope_member_expression_evaluate(bithenge_expression_t *base,
503 bithenge_scope_t *scope, bithenge_node_t **out)
504{
505 scope_member_expression_t *self = expression_as_scope_member(base);
506 for (; scope && !bithenge_scope_is_barrier(scope);
507 scope = bithenge_scope_outer(scope)) {
508 bithenge_node_t *cur = bithenge_scope_get_current_node(scope);
509 if (!cur)
510 continue;
511 bithenge_node_inc_ref(self->key);
512 int rc = bithenge_node_get(cur, self->key, out);
513 bithenge_node_dec_ref(cur);
514 if (rc != ENOENT) /* EOK or error */
515 return rc;
516 }
517 return bithenge_scope_error(scope, "No scope member %t", self->key);
518}
519
520static void scope_member_expression_destroy(bithenge_expression_t *base)
521{
522 scope_member_expression_t *self = expression_as_scope_member(base);
523 bithenge_node_dec_ref(self->key);
524 free(self);
525}
526
527static const bithenge_expression_ops_t scope_member_expression_ops = {
528 .evaluate = scope_member_expression_evaluate,
529 .destroy = scope_member_expression_destroy,
530};
531
532int bithenge_scope_member_expression(bithenge_expression_t **out,
533 bithenge_node_t *key)
534{
535 int rc;
536 scope_member_expression_t *self = malloc(sizeof(*self));
537 if (!self) {
538 rc = ENOMEM;
539 goto error;
540 }
541
542 rc = bithenge_init_expression(scope_member_as_expression(self),
543 &scope_member_expression_ops);
544 if (rc != EOK)
545 goto error;
546
547 self->key = key;
548 *out = scope_member_as_expression(self);
549 return EOK;
550
551error:
552 bithenge_node_dec_ref(key);
553 free(self);
554 return rc;
555}
556
557
558
559/***************** subblob_expression *****************/
560
561typedef struct {
562 bithenge_expression_t base;
563 bithenge_expression_t *blob, *start, *limit;
564 bool absolute_limit;
565} subblob_expression_t;
566
567static subblob_expression_t *expression_as_subblob(bithenge_expression_t *base)
568{
569 return (subblob_expression_t *)base;
570}
571
572static bithenge_expression_t *subblob_as_expression(subblob_expression_t *expr)
573{
574 return &expr->base;
575}
576
577static int subblob_expression_evaluate(bithenge_expression_t *base,
578 bithenge_scope_t *scope, bithenge_node_t **out)
579{
580 subblob_expression_t *self = expression_as_subblob(base);
581 bithenge_node_t *start_node;
582 int rc = bithenge_expression_evaluate(self->start, scope, &start_node);
583 if (rc != EOK)
584 return rc;
585 if (bithenge_node_type(start_node) != BITHENGE_NODE_INTEGER) {
586 bithenge_node_dec_ref(start_node);
587 return EINVAL;
588 }
589 bithenge_int_t start = bithenge_integer_node_value(start_node);
590 bithenge_node_dec_ref(start_node);
591
592 bithenge_int_t limit = -1;
593 if (self->limit) {
594 bithenge_node_t *limit_node;
595 rc = bithenge_expression_evaluate(self->limit, scope,
596 &limit_node);
597 if (rc != EOK)
598 return rc;
599 if (bithenge_node_type(limit_node) != BITHENGE_NODE_INTEGER) {
600 bithenge_node_dec_ref(limit_node);
601 return EINVAL;
602 }
603 limit = bithenge_integer_node_value(limit_node);
604 bithenge_node_dec_ref(limit_node);
605 if (self->absolute_limit)
606 limit -= start;
607 }
608
609 if (start < 0 || (self->limit && limit < 0))
610 return EINVAL;
611
612 bithenge_node_t *blob;
613 rc = bithenge_expression_evaluate(self->blob, scope, &blob);
614 if (rc != EOK)
615 return rc;
616 if (bithenge_node_type(blob) != BITHENGE_NODE_BLOB) {
617 bithenge_node_dec_ref(blob);
618 return EINVAL;
619 }
620
621 if (self->limit)
622 return bithenge_new_subblob(out, bithenge_node_as_blob(blob),
623 start, limit);
624 else
625 return bithenge_new_offset_blob(out,
626 bithenge_node_as_blob(blob), start);
627}
628
629static void subblob_expression_destroy(bithenge_expression_t *base)
630{
631 subblob_expression_t *self = expression_as_subblob(base);
632 bithenge_expression_dec_ref(self->blob);
633 bithenge_expression_dec_ref(self->start);
634 bithenge_expression_dec_ref(self->limit);
635 free(self);
636}
637
638static const bithenge_expression_ops_t subblob_expression_ops = {
639 .evaluate = subblob_expression_evaluate,
640 .destroy = subblob_expression_destroy,
641};
642
643/** Create an expression that gets a subblob. Takes references to @a blob,
644 * @a start, and @a limit.
645 * @param[out] out Holds the new expression.
646 * @param blob Calculates the blob.
647 * @param start Calculates the start offset within the blob.
648 * @param limit Calculates the limit. Can be NULL, in which case an offset blob
649 * is returned.
650 * @param absolute_limit If true, the limit is an absolute offset; otherwise,
651 * it is relative to the start.
652 * @return EOK on success or an error code from errno.h. */
653int bithenge_subblob_expression(bithenge_expression_t **out,
654 bithenge_expression_t *blob, bithenge_expression_t *start,
655 bithenge_expression_t *limit, bool absolute_limit)
656{
657 int rc;
658 subblob_expression_t *self = malloc(sizeof(*self));
659 if (!self) {
660 rc = ENOMEM;
661 goto error;
662 }
663
664 rc = bithenge_init_expression(subblob_as_expression(self),
665 &subblob_expression_ops);
666 if (rc != EOK)
667 goto error;
668
669 self->blob = blob;
670 self->start = start;
671 self->limit = limit;
672 self->absolute_limit = absolute_limit;
673 *out = subblob_as_expression(self);
674 return EOK;
675
676error:
677 bithenge_expression_dec_ref(blob);
678 bithenge_expression_dec_ref(start);
679 bithenge_expression_dec_ref(limit);
680 free(self);
681 return rc;
682}
683
684/***************** param_wrapper *****************/
685
686typedef struct {
687 bithenge_transform_t base;
688 bithenge_transform_t *transform;
689 bithenge_expression_t **params;
690} param_wrapper_t;
691
692static inline bithenge_transform_t *param_wrapper_as_transform(
693 param_wrapper_t *self)
694{
695 return &self->base;
696}
697
698static inline param_wrapper_t *transform_as_param_wrapper(
699 bithenge_transform_t *base)
700{
701 return (param_wrapper_t *)base;
702}
703
704static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
705 *inner, bithenge_scope_t *outer)
706{
707 int rc;
708 int num_params = bithenge_transform_num_params(self->transform);
709 rc = bithenge_scope_alloc_params(inner, num_params);
710 if (rc != EOK)
711 return rc;
712 for (int i = 0; i < num_params; i++) {
713 bithenge_node_t *node;
714 rc = bithenge_expression_evaluate(self->params[i], outer,
715 &node);
716 if (rc != EOK)
717 return rc;
718 rc = bithenge_scope_set_param(inner, i, node);
719 if (rc != EOK)
720 return rc;
721 }
722 return EOK;
723}
724
725static int param_wrapper_apply(bithenge_transform_t *base,
726 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
727{
728 param_wrapper_t *self = transform_as_param_wrapper(base);
729 bithenge_scope_t *inner;
730 int rc = bithenge_scope_new(&inner, outer);
731 if (rc != EOK)
732 return rc;
733 rc = param_wrapper_fill_scope(self, inner, outer);
734 if (rc != EOK)
735 goto error;
736
737 rc = bithenge_transform_apply(self->transform, inner, in, out);
738 in = NULL;
739
740error:
741 bithenge_scope_dec_ref(inner);
742 return rc;
743}
744
745static int param_wrapper_prefix_length(bithenge_transform_t *base,
746 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
747{
748 param_wrapper_t *self = transform_as_param_wrapper(base);
749 bithenge_scope_t *inner;
750 int rc = bithenge_scope_new(&inner, outer);
751 if (rc != EOK)
752 return rc;
753 rc = param_wrapper_fill_scope(self, inner, outer);
754 if (rc != EOK)
755 goto error;
756
757 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
758 in = NULL;
759
760error:
761 bithenge_scope_dec_ref(inner);
762 return rc;
763}
764
765static int param_wrapper_prefix_apply(bithenge_transform_t *base,
766 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
767 aoff64_t *out_length)
768{
769 param_wrapper_t *self = transform_as_param_wrapper(base);
770 bithenge_scope_t *inner;
771 int rc = bithenge_scope_new(&inner, outer);
772 if (rc != EOK)
773 return rc;
774 rc = param_wrapper_fill_scope(self, inner, outer);
775 if (rc != EOK)
776 goto error;
777
778 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
779 out_node, out_length);
780
781error:
782 bithenge_scope_dec_ref(inner);
783 return rc;
784}
785
786static void param_wrapper_destroy(bithenge_transform_t *base)
787{
788 param_wrapper_t *self = transform_as_param_wrapper(base);
789 int num_params = bithenge_transform_num_params(self->transform);
790 bithenge_transform_dec_ref(self->transform);
791 for (int i = 0; i < num_params; i++)
792 bithenge_expression_dec_ref(self->params[i]);
793 free(self->params);
794 free(self);
795}
796
797static const bithenge_transform_ops_t param_wrapper_ops = {
798 .apply = param_wrapper_apply,
799 .prefix_length = param_wrapper_prefix_length,
800 .prefix_apply = param_wrapper_prefix_apply,
801 .destroy = param_wrapper_destroy,
802};
803
804/** Create a transform that calculates parameters for another transform. Takes
805 * ownership of @a transform, @a params, and each element of @a params. The
806 * number of parameters must be correct.
807 * @param[out] out Holds the new transform.
808 * @param transform The transform for which parameters are calculated.
809 * @param params The expressions used to calculate the parameters.
810 * @return EOK on success or an error code from errno.h. */
811int bithenge_param_wrapper(bithenge_transform_t **out,
812 bithenge_transform_t *transform, bithenge_expression_t **params)
813{
814 int rc;
815 int num_params = bithenge_transform_num_params(transform);
816 param_wrapper_t *self = malloc(sizeof(*self));
817 if (!self) {
818 rc = ENOMEM;
819 goto error;
820 }
821
822 rc = bithenge_init_transform(param_wrapper_as_transform(self),
823 &param_wrapper_ops, 0);
824 if (rc != EOK)
825 goto error;
826
827 self->transform = transform;
828 self->params = params;
829 *out = param_wrapper_as_transform(self);
830 return EOK;
831
832error:
833 free(self);
834 for (int i = 0; i < num_params; i++)
835 bithenge_expression_dec_ref(params[i]);
836 free(params);
837 bithenge_transform_dec_ref(transform);
838 return rc;
839}
840
841
842
843/***************** expression_transform *****************/
844
845/* Also used by inputless_transform. */
846typedef struct {
847 bithenge_transform_t base;
848 bithenge_expression_t *expr;
849} expression_transform_t;
850
851static inline bithenge_transform_t *expression_as_transform(
852 expression_transform_t *self)
853{
854 return &self->base;
855}
856
857static inline expression_transform_t *transform_as_expression(
858 bithenge_transform_t *base)
859{
860 return (expression_transform_t *)base;
861}
862
863static int expression_transform_apply(bithenge_transform_t *base,
864 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
865{
866 expression_transform_t *self = transform_as_expression(base);
867 bithenge_scope_t *inner;
868 int rc = bithenge_scope_new(&inner, scope);
869 if (rc != EOK)
870 return rc;
871 bithenge_scope_set_in_node(inner, in);
872 rc = bithenge_expression_evaluate(self->expr, inner, out);
873 bithenge_scope_dec_ref(inner);
874 return rc;
875}
876
877/* Also used by inputless_transform. */
878static void expression_transform_destroy(bithenge_transform_t *base)
879{
880 expression_transform_t *self = transform_as_expression(base);
881 bithenge_expression_dec_ref(self->expr);
882 free(self);
883}
884
885static const bithenge_transform_ops_t expression_transform_ops = {
886 .apply = expression_transform_apply,
887 .destroy = expression_transform_destroy,
888};
889
890/** Create a transform that evaluates an expression on the input node. Takes a
891 * reference to the expression.
892 * @param[out] out Holds the new transform.
893 * @param expr The expression to evaluate.
894 * @return EOK on success or an error code from errno.h. */
895int bithenge_expression_transform(bithenge_transform_t ** out,
896 bithenge_expression_t *expr)
897{
898 int rc;
899 expression_transform_t *self = malloc(sizeof(*self));
900 if (!self) {
901 rc = ENOMEM;
902 goto error;
903 }
904
905 rc = bithenge_init_transform(expression_as_transform(self),
906 &expression_transform_ops, 0);
907 if (rc != EOK)
908 goto error;
909
910 self->expr = expr;
911 *out = expression_as_transform(self);
912 return EOK;
913
914error:
915 free(self);
916 bithenge_expression_dec_ref(expr);
917 return rc;
918}
919
920
921
922/***************** inputless_transform *****************/
923
924static int inputless_transform_prefix_length(bithenge_transform_t *base,
925 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
926{
927 *out = 0;
928 return EOK;
929}
930
931static int inputless_transform_prefix_apply(bithenge_transform_t *base,
932 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
933 aoff64_t *out_size)
934{
935 expression_transform_t *self = transform_as_expression(base);
936 if (out_size)
937 *out_size = 0;
938 return bithenge_expression_evaluate(self->expr, scope, out_node);
939}
940
941static const bithenge_transform_ops_t inputless_transform_ops = {
942 .prefix_length = inputless_transform_prefix_length,
943 .prefix_apply = inputless_transform_prefix_apply,
944 .destroy = expression_transform_destroy,
945};
946
947/** Create a transform that takes an empty blob and produces the result of an
948 * expression. Takes a reference to the expression.
949 * @param[out] out Holds the new transform.
950 * @param expr The expression to evaluate.
951 * @return EOK on success or an error code from errno.h. */
952int bithenge_inputless_transform(bithenge_transform_t ** out,
953 bithenge_expression_t *expr)
954{
955 int rc;
956 expression_transform_t *self = malloc(sizeof(*self));
957 if (!self) {
958 rc = ENOMEM;
959 goto error;
960 }
961
962 rc = bithenge_init_transform(expression_as_transform(self),
963 &inputless_transform_ops, 0);
964 if (rc != EOK)
965 goto error;
966
967 self->expr = expr;
968 *out = expression_as_transform(self);
969 return EOK;
970
971error:
972 free(self);
973 bithenge_expression_dec_ref(expr);
974 return rc;
975}
976
977
978
979/***************** concat_blob *****************/
980
981typedef struct {
982 bithenge_blob_t base;
983 bithenge_blob_t *a, *b;
984 aoff64_t a_size;
985 bithenge_expression_t *b_expr;
986 bithenge_scope_t *scope;
987} concat_blob_t;
988
989static inline concat_blob_t *blob_as_concat(bithenge_blob_t *base)
990{
991 return (concat_blob_t *)base;
992}
993
994static inline bithenge_blob_t *concat_as_blob(concat_blob_t *blob)
995{
996 return &blob->base;
997}
998
999static int concat_blob_evaluate_b(concat_blob_t *self)
1000{
1001 if (self->b)
1002 return EOK;
1003 bithenge_node_t *b_node;
1004 int rc = bithenge_expression_evaluate(self->b_expr, self->scope,
1005 &b_node);
1006 if (rc != EOK)
1007 return rc;
1008 if (bithenge_node_type(b_node) != BITHENGE_NODE_BLOB) {
1009 bithenge_node_dec_ref(b_node);
1010 return bithenge_scope_error(self->scope,
1011 "Concatenation arguments must be blobs");
1012 }
1013 self->b = bithenge_node_as_blob(b_node);
1014 bithenge_expression_dec_ref(self->b_expr);
1015 bithenge_scope_dec_ref(self->scope);
1016 self->b_expr = NULL;
1017 self->scope = NULL;
1018 return EOK;
1019}
1020
1021static int concat_blob_size(bithenge_blob_t *base, aoff64_t *size)
1022{
1023 concat_blob_t *self = blob_as_concat(base);
1024 int rc = concat_blob_evaluate_b(self);
1025 if (rc != EOK)
1026 return rc;
1027 rc = bithenge_blob_size(self->b, size);
1028 *size += self->a_size;
1029 return rc;
1030}
1031
1032static int concat_blob_read(bithenge_blob_t *base, aoff64_t offset,
1033 char *buffer, aoff64_t *size)
1034{
1035 int rc;
1036 concat_blob_t *self = blob_as_concat(base);
1037
1038 aoff64_t a_size = 0, b_size = 0;
1039 if (offset < self->a_size) {
1040 a_size = *size;
1041 rc = bithenge_blob_read(self->a, offset, buffer, &a_size);
1042 if (rc != EOK)
1043 return rc;
1044 }
1045 if (offset + *size > self->a_size) {
1046 rc = concat_blob_evaluate_b(self);
1047 if (rc != EOK)
1048 return rc;
1049 b_size = *size - a_size;
1050 rc = bithenge_blob_read(self->b,
1051 offset + a_size - self->a_size, buffer + a_size, &b_size);
1052 if (rc != EOK)
1053 return rc;
1054 }
1055 assert(a_size + b_size <= *size);
1056 *size = a_size + b_size;
1057 return EOK;
1058}
1059
1060static int concat_blob_read_bits(bithenge_blob_t *base, aoff64_t offset,
1061 char *buffer, aoff64_t *size, bool little_endian)
1062{
1063 int rc;
1064 concat_blob_t *self = blob_as_concat(base);
1065
1066 aoff64_t a_size = 0, b_size = 0;
1067 if (offset < self->a_size) {
1068 a_size = *size;
1069 rc = bithenge_blob_read_bits(self->a, offset, buffer, &a_size,
1070 little_endian);
1071 if (rc != EOK)
1072 return rc;
1073 }
1074 if (offset + *size > self->a_size) {
1075 rc = concat_blob_evaluate_b(self);
1076 if (rc != EOK)
1077 return rc;
1078 b_size = *size - a_size;
1079 assert(a_size % 8 == 0); /* TODO: don't require this */
1080 rc = bithenge_blob_read_bits(self->b,
1081 offset + a_size - self->a_size, buffer + a_size / 8,
1082 &b_size, little_endian);
1083 if (rc != EOK)
1084 return rc;
1085 }
1086 assert(a_size + b_size <= *size);
1087 *size = a_size + b_size;
1088 return EOK;
1089}
1090
1091static void concat_blob_destroy(bithenge_blob_t *base)
1092{
1093 concat_blob_t *self = blob_as_concat(base);
1094 bithenge_blob_dec_ref(self->a);
1095 bithenge_blob_dec_ref(self->b);
1096 bithenge_expression_dec_ref(self->b_expr);
1097 bithenge_scope_dec_ref(self->scope);
1098 free(self);
1099}
1100
1101static const bithenge_random_access_blob_ops_t concat_blob_ops = {
1102 .size = concat_blob_size,
1103 .read = concat_blob_read,
1104 .read_bits = concat_blob_read_bits,
1105 .destroy = concat_blob_destroy,
1106};
1107
1108/** Create a concatenated blob. Takes references to @a a and @a b.
1109 * @param[out] out Holds the new blob.
1110 * @param a The first blob.
1111 * @param b The second blob.
1112 * @return EOK on success or an error code from errno.h. */
1113int bithenge_concat_blob(bithenge_node_t **out, bithenge_blob_t *a,
1114 bithenge_blob_t *b)
1115{
1116 assert(out);
1117 assert(a);
1118 assert(b);
1119 int rc;
1120 concat_blob_t *self = malloc(sizeof(*self));
1121 if (!self) {
1122 rc = ENOMEM;
1123 goto error;
1124 }
1125
1126 rc = bithenge_blob_size(a, &self->a_size);
1127 if (rc != EOK)
1128 goto error;
1129
1130 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1131 &concat_blob_ops);
1132 if (rc != EOK)
1133 goto error;
1134 self->a = a;
1135 self->b = b;
1136 self->b_expr = NULL;
1137 self->scope = NULL;
1138 *out = bithenge_blob_as_node(concat_as_blob(self));
1139 return EOK;
1140
1141error:
1142 bithenge_blob_dec_ref(a);
1143 bithenge_blob_dec_ref(b);
1144 free(self);
1145 return rc;
1146}
1147
1148/** Create a lazy concatenated blob. Takes references to @a a, @a b_expr, and
1149 * @a scope.
1150 * @param[out] out Holds the new blob.
1151 * @param a The first blob.
1152 * @param b_expr An expression to calculate the second blob.
1153 * @param scope The scope in which @a b_expr should be evaluated.
1154 * @return EOK on success or an error code from errno.h. */
1155int bithenge_concat_blob_lazy(bithenge_node_t **out, bithenge_blob_t *a,
1156 bithenge_expression_t *b_expr, bithenge_scope_t *scope)
1157{
1158 assert(out);
1159 assert(a);
1160 assert(b_expr);
1161 assert(scope);
1162 int rc;
1163 concat_blob_t *self = malloc(sizeof(*self));
1164 if (!self) {
1165 rc = ENOMEM;
1166 goto error;
1167 }
1168
1169 rc = bithenge_blob_size(a, &self->a_size);
1170 if (rc != EOK)
1171 goto error;
1172
1173 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1174 &concat_blob_ops);
1175 if (rc != EOK)
1176 goto error;
1177 self->a = a;
1178 self->b = NULL;
1179 self->b_expr = b_expr;
1180 self->scope = scope;
1181 *out = bithenge_blob_as_node(concat_as_blob(self));
1182 return EOK;
1183
1184error:
1185 bithenge_blob_dec_ref(a);
1186 bithenge_expression_dec_ref(b_expr);
1187 bithenge_scope_dec_ref(scope);
1188 free(self);
1189 return rc;
1190}
1191
1192/** @}
1193 */
Note: See TracBrowser for help on using the repository browser.