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

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

Fix vertical spacing with new Ccheck revision.

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