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

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

Fix block comment formatting (ccheck).

  • 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
70
71/***************** binary_expression *****************/
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
287/***************** in_node_expression *****************/
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
324/***************** current_node_expression *****************/
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
357/***************** param_expression *****************/
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
420/***************** const_expression *****************/
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
492/***************** scope_member_expression *****************/
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
575/***************** subblob_expression *****************/
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/***************** param_wrapper *****************/
702
703typedef struct {
704 bithenge_transform_t base;
705 bithenge_transform_t *transform;
706 bithenge_expression_t **params;
707} param_wrapper_t;
708
709static inline bithenge_transform_t *param_wrapper_as_transform(
710 param_wrapper_t *self)
711{
712 return &self->base;
713}
714
715static inline param_wrapper_t *transform_as_param_wrapper(
716 bithenge_transform_t *base)
717{
718 return (param_wrapper_t *)base;
719}
720
721static errno_t param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
722 *inner, bithenge_scope_t *outer)
723{
724 errno_t rc;
725 int num_params = bithenge_transform_num_params(self->transform);
726 rc = bithenge_scope_alloc_params(inner, num_params);
727 if (rc != EOK)
728 return rc;
729 for (int i = 0; i < num_params; i++) {
730 bithenge_node_t *node;
731 rc = bithenge_expression_evaluate(self->params[i], outer,
732 &node);
733 if (rc != EOK)
734 return rc;
735 rc = bithenge_scope_set_param(inner, i, node);
736 if (rc != EOK)
737 return rc;
738 }
739 return EOK;
740}
741
742static errno_t param_wrapper_apply(bithenge_transform_t *base,
743 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
744{
745 param_wrapper_t *self = transform_as_param_wrapper(base);
746 bithenge_scope_t *inner;
747 errno_t rc = bithenge_scope_new(&inner, outer);
748 if (rc != EOK)
749 return rc;
750 rc = param_wrapper_fill_scope(self, inner, outer);
751 if (rc != EOK)
752 goto error;
753
754 rc = bithenge_transform_apply(self->transform, inner, in, out);
755 in = NULL;
756
757error:
758 bithenge_scope_dec_ref(inner);
759 return rc;
760}
761
762static errno_t param_wrapper_prefix_length(bithenge_transform_t *base,
763 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
764{
765 param_wrapper_t *self = transform_as_param_wrapper(base);
766 bithenge_scope_t *inner;
767 errno_t rc = bithenge_scope_new(&inner, outer);
768 if (rc != EOK)
769 return rc;
770 rc = param_wrapper_fill_scope(self, inner, outer);
771 if (rc != EOK)
772 goto error;
773
774 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
775 in = NULL;
776
777error:
778 bithenge_scope_dec_ref(inner);
779 return rc;
780}
781
782static errno_t param_wrapper_prefix_apply(bithenge_transform_t *base,
783 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
784 aoff64_t *out_length)
785{
786 param_wrapper_t *self = transform_as_param_wrapper(base);
787 bithenge_scope_t *inner;
788 errno_t rc = bithenge_scope_new(&inner, outer);
789 if (rc != EOK)
790 return rc;
791 rc = param_wrapper_fill_scope(self, inner, outer);
792 if (rc != EOK)
793 goto error;
794
795 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
796 out_node, out_length);
797
798error:
799 bithenge_scope_dec_ref(inner);
800 return rc;
801}
802
803static void param_wrapper_destroy(bithenge_transform_t *base)
804{
805 param_wrapper_t *self = transform_as_param_wrapper(base);
806 int num_params = bithenge_transform_num_params(self->transform);
807 bithenge_transform_dec_ref(self->transform);
808 for (int i = 0; i < num_params; i++)
809 bithenge_expression_dec_ref(self->params[i]);
810 free(self->params);
811 free(self);
812}
813
814static const bithenge_transform_ops_t param_wrapper_ops = {
815 .apply = param_wrapper_apply,
816 .prefix_length = param_wrapper_prefix_length,
817 .prefix_apply = param_wrapper_prefix_apply,
818 .destroy = param_wrapper_destroy,
819};
820
821/** Create a transform that calculates parameters for another transform. Takes
822 * ownership of @a transform, @a params, and each element of @a params. The
823 * number of parameters must be correct.
824 * @param[out] out Holds the new transform.
825 * @param transform The transform for which parameters are calculated.
826 * @param params The expressions used to calculate the parameters.
827 * @return EOK on success or an error code from errno.h.
828 */
829errno_t bithenge_param_wrapper(bithenge_transform_t **out,
830 bithenge_transform_t *transform, bithenge_expression_t **params)
831{
832 errno_t rc;
833 int num_params = bithenge_transform_num_params(transform);
834 param_wrapper_t *self = malloc(sizeof(*self));
835 if (!self) {
836 rc = ENOMEM;
837 goto error;
838 }
839
840 rc = bithenge_init_transform(param_wrapper_as_transform(self),
841 &param_wrapper_ops, 0);
842 if (rc != EOK)
843 goto error;
844
845 self->transform = transform;
846 self->params = params;
847 *out = param_wrapper_as_transform(self);
848 return EOK;
849
850error:
851 free(self);
852 for (int i = 0; i < num_params; i++)
853 bithenge_expression_dec_ref(params[i]);
854 free(params);
855 bithenge_transform_dec_ref(transform);
856 return rc;
857}
858
859
860
861/***************** expression_transform *****************/
862
863/* Also used by inputless_transform. */
864typedef struct {
865 bithenge_transform_t base;
866 bithenge_expression_t *expr;
867} expression_transform_t;
868
869static inline bithenge_transform_t *expression_as_transform(
870 expression_transform_t *self)
871{
872 return &self->base;
873}
874
875static inline expression_transform_t *transform_as_expression(
876 bithenge_transform_t *base)
877{
878 return (expression_transform_t *)base;
879}
880
881static errno_t expression_transform_apply(bithenge_transform_t *base,
882 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
883{
884 expression_transform_t *self = transform_as_expression(base);
885 bithenge_scope_t *inner;
886 errno_t rc = bithenge_scope_new(&inner, scope);
887 if (rc != EOK)
888 return rc;
889 bithenge_scope_set_in_node(inner, in);
890 rc = bithenge_expression_evaluate(self->expr, inner, out);
891 bithenge_scope_dec_ref(inner);
892 return rc;
893}
894
895/* Also used by inputless_transform. */
896static void expression_transform_destroy(bithenge_transform_t *base)
897{
898 expression_transform_t *self = transform_as_expression(base);
899 bithenge_expression_dec_ref(self->expr);
900 free(self);
901}
902
903static const bithenge_transform_ops_t expression_transform_ops = {
904 .apply = expression_transform_apply,
905 .destroy = expression_transform_destroy,
906};
907
908/** Create a transform that evaluates an expression on the input node. Takes a
909 * reference to the expression.
910 * @param[out] out Holds the new transform.
911 * @param expr The expression to evaluate.
912 * @return EOK on success or an error code from errno.h.
913 */
914errno_t bithenge_expression_transform(bithenge_transform_t **out,
915 bithenge_expression_t *expr)
916{
917 errno_t rc;
918 expression_transform_t *self = malloc(sizeof(*self));
919 if (!self) {
920 rc = ENOMEM;
921 goto error;
922 }
923
924 rc = bithenge_init_transform(expression_as_transform(self),
925 &expression_transform_ops, 0);
926 if (rc != EOK)
927 goto error;
928
929 self->expr = expr;
930 *out = expression_as_transform(self);
931 return EOK;
932
933error:
934 free(self);
935 bithenge_expression_dec_ref(expr);
936 return rc;
937}
938
939
940
941/***************** inputless_transform *****************/
942
943static errno_t inputless_transform_prefix_length(bithenge_transform_t *base,
944 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
945{
946 *out = 0;
947 return EOK;
948}
949
950static errno_t inputless_transform_prefix_apply(bithenge_transform_t *base,
951 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
952 aoff64_t *out_size)
953{
954 expression_transform_t *self = transform_as_expression(base);
955 if (out_size)
956 *out_size = 0;
957 return bithenge_expression_evaluate(self->expr, scope, out_node);
958}
959
960static const bithenge_transform_ops_t inputless_transform_ops = {
961 .prefix_length = inputless_transform_prefix_length,
962 .prefix_apply = inputless_transform_prefix_apply,
963 .destroy = expression_transform_destroy,
964};
965
966/** Create a transform that takes an empty blob and produces the result of an
967 * expression. Takes a reference to the expression.
968 * @param[out] out Holds the new transform.
969 * @param expr The expression to evaluate.
970 * @return EOK on success or an error code from errno.h.
971 */
972errno_t bithenge_inputless_transform(bithenge_transform_t **out,
973 bithenge_expression_t *expr)
974{
975 errno_t rc;
976 expression_transform_t *self = malloc(sizeof(*self));
977 if (!self) {
978 rc = ENOMEM;
979 goto error;
980 }
981
982 rc = bithenge_init_transform(expression_as_transform(self),
983 &inputless_transform_ops, 0);
984 if (rc != EOK)
985 goto error;
986
987 self->expr = expr;
988 *out = expression_as_transform(self);
989 return EOK;
990
991error:
992 free(self);
993 bithenge_expression_dec_ref(expr);
994 return rc;
995}
996
997
998
999/***************** concat_blob *****************/
1000
1001typedef struct {
1002 bithenge_blob_t base;
1003 bithenge_blob_t *a, *b;
1004 aoff64_t a_size;
1005 bithenge_expression_t *b_expr;
1006 bithenge_scope_t *scope;
1007} concat_blob_t;
1008
1009static inline concat_blob_t *blob_as_concat(bithenge_blob_t *base)
1010{
1011 return (concat_blob_t *)base;
1012}
1013
1014static inline bithenge_blob_t *concat_as_blob(concat_blob_t *blob)
1015{
1016 return &blob->base;
1017}
1018
1019static errno_t concat_blob_evaluate_b(concat_blob_t *self)
1020{
1021 if (self->b)
1022 return EOK;
1023 bithenge_node_t *b_node;
1024 errno_t rc = bithenge_expression_evaluate(self->b_expr, self->scope,
1025 &b_node);
1026 if (rc != EOK)
1027 return rc;
1028 if (bithenge_node_type(b_node) != BITHENGE_NODE_BLOB) {
1029 bithenge_node_dec_ref(b_node);
1030 return bithenge_scope_error(self->scope,
1031 "Concatenation arguments must be blobs");
1032 }
1033 self->b = bithenge_node_as_blob(b_node);
1034 bithenge_expression_dec_ref(self->b_expr);
1035 bithenge_scope_dec_ref(self->scope);
1036 self->b_expr = NULL;
1037 self->scope = NULL;
1038 return EOK;
1039}
1040
1041static errno_t concat_blob_size(bithenge_blob_t *base, aoff64_t *size)
1042{
1043 concat_blob_t *self = blob_as_concat(base);
1044 errno_t rc = concat_blob_evaluate_b(self);
1045 if (rc != EOK)
1046 return rc;
1047 rc = bithenge_blob_size(self->b, size);
1048 *size += self->a_size;
1049 return rc;
1050}
1051
1052static errno_t concat_blob_read(bithenge_blob_t *base, aoff64_t offset,
1053 char *buffer, aoff64_t *size)
1054{
1055 errno_t rc;
1056 concat_blob_t *self = blob_as_concat(base);
1057
1058 aoff64_t a_size = 0, b_size = 0;
1059 if (offset < self->a_size) {
1060 a_size = *size;
1061 rc = bithenge_blob_read(self->a, offset, buffer, &a_size);
1062 if (rc != EOK)
1063 return rc;
1064 }
1065 if (offset + *size > self->a_size) {
1066 rc = concat_blob_evaluate_b(self);
1067 if (rc != EOK)
1068 return rc;
1069 b_size = *size - a_size;
1070 rc = bithenge_blob_read(self->b,
1071 offset + a_size - self->a_size, buffer + a_size, &b_size);
1072 if (rc != EOK)
1073 return rc;
1074 }
1075 assert(a_size + b_size <= *size);
1076 *size = a_size + b_size;
1077 return EOK;
1078}
1079
1080static errno_t concat_blob_read_bits(bithenge_blob_t *base, aoff64_t offset,
1081 char *buffer, aoff64_t *size, bool little_endian)
1082{
1083 errno_t rc;
1084 concat_blob_t *self = blob_as_concat(base);
1085
1086 aoff64_t a_size = 0, b_size = 0;
1087 if (offset < self->a_size) {
1088 a_size = *size;
1089 rc = bithenge_blob_read_bits(self->a, offset, buffer, &a_size,
1090 little_endian);
1091 if (rc != EOK)
1092 return rc;
1093 }
1094 if (offset + *size > self->a_size) {
1095 rc = concat_blob_evaluate_b(self);
1096 if (rc != EOK)
1097 return rc;
1098 b_size = *size - a_size;
1099 assert(a_size % 8 == 0); /* TODO: don't require this */
1100 rc = bithenge_blob_read_bits(self->b,
1101 offset + a_size - self->a_size, buffer + a_size / 8,
1102 &b_size, little_endian);
1103 if (rc != EOK)
1104 return rc;
1105 }
1106 assert(a_size + b_size <= *size);
1107 *size = a_size + b_size;
1108 return EOK;
1109}
1110
1111static void concat_blob_destroy(bithenge_blob_t *base)
1112{
1113 concat_blob_t *self = blob_as_concat(base);
1114 bithenge_blob_dec_ref(self->a);
1115 bithenge_blob_dec_ref(self->b);
1116 bithenge_expression_dec_ref(self->b_expr);
1117 bithenge_scope_dec_ref(self->scope);
1118 free(self);
1119}
1120
1121static const bithenge_random_access_blob_ops_t concat_blob_ops = {
1122 .size = concat_blob_size,
1123 .read = concat_blob_read,
1124 .read_bits = concat_blob_read_bits,
1125 .destroy = concat_blob_destroy,
1126};
1127
1128/** Create a concatenated blob. Takes references to @a a and @a b.
1129 * @param[out] out Holds the new blob.
1130 * @param a The first blob.
1131 * @param b The second blob.
1132 * @return EOK on success or an error code from errno.h.
1133 */
1134errno_t bithenge_concat_blob(bithenge_node_t **out, bithenge_blob_t *a,
1135 bithenge_blob_t *b)
1136{
1137 assert(out);
1138 assert(a);
1139 assert(b);
1140 errno_t rc;
1141 concat_blob_t *self = malloc(sizeof(*self));
1142 if (!self) {
1143 rc = ENOMEM;
1144 goto error;
1145 }
1146
1147 rc = bithenge_blob_size(a, &self->a_size);
1148 if (rc != EOK)
1149 goto error;
1150
1151 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1152 &concat_blob_ops);
1153 if (rc != EOK)
1154 goto error;
1155 self->a = a;
1156 self->b = b;
1157 self->b_expr = NULL;
1158 self->scope = NULL;
1159 *out = bithenge_blob_as_node(concat_as_blob(self));
1160 return EOK;
1161
1162error:
1163 bithenge_blob_dec_ref(a);
1164 bithenge_blob_dec_ref(b);
1165 free(self);
1166 return rc;
1167}
1168
1169/** Create a lazy concatenated blob. Takes references to @a a, @a b_expr, and
1170 * @a scope.
1171 * @param[out] out Holds the new blob.
1172 * @param a The first blob.
1173 * @param b_expr An expression to calculate the second blob.
1174 * @param scope The scope in which @a b_expr should be evaluated.
1175 * @return EOK on success or an error code from errno.h.
1176 */
1177errno_t bithenge_concat_blob_lazy(bithenge_node_t **out, bithenge_blob_t *a,
1178 bithenge_expression_t *b_expr, bithenge_scope_t *scope)
1179{
1180 assert(out);
1181 assert(a);
1182 assert(b_expr);
1183 assert(scope);
1184 errno_t rc;
1185 concat_blob_t *self = malloc(sizeof(*self));
1186 if (!self) {
1187 rc = ENOMEM;
1188 goto error;
1189 }
1190
1191 rc = bithenge_blob_size(a, &self->a_size);
1192 if (rc != EOK)
1193 goto error;
1194
1195 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1196 &concat_blob_ops);
1197 if (rc != EOK)
1198 goto error;
1199 self->a = a;
1200 self->b = NULL;
1201 self->b_expr = b_expr;
1202 self->scope = scope;
1203 *out = bithenge_blob_as_node(concat_as_blob(self));
1204 return EOK;
1205
1206error:
1207 bithenge_blob_dec_ref(a);
1208 bithenge_expression_dec_ref(b_expr);
1209 bithenge_scope_dec_ref(scope);
1210 free(self);
1211 return rc;
1212}
1213
1214/** @}
1215 */
Note: See TracBrowser for help on using the repository browser.