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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d1582b50 was d1582b50, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Fix spacing in single-line comments using latest ccheck

This found incorrectly formatted section comments (with blocks of
asterisks or dashes). I strongly believe against using section comments
but I am not simply removing them since that would probably be
controversial.

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