source: mainline/uspace/lib/bithenge/src/expression.c@ eec201d

Last change on this file since eec201d was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

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