source: mainline/uspace/lib/bithenge/expression.c@ 5e514c0

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

Bithenge: add fake system call errors to test error handling

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