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

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

Fix spacing in single-line comments using latest ccheck

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

  • Property mode set to 100644
File size: 31.1 KB
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
[d1582b50]69/*
70 * binary_expression
71 */
[a66ea217]72
[78d3a00]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
[b7fd2a0]91static errno_t binary_expression_evaluate(bithenge_expression_t *base,
[78d3a00]92 bithenge_scope_t *scope, bithenge_node_t **out)
93{
[b7fd2a0]94 errno_t rc;
[78d3a00]95 binary_expression_t *self = expression_as_binary(base);
96 bithenge_node_t *a, *b;
[3a7356dc]97 rc = bithenge_expression_evaluate(self->a, scope, &a);
[78d3a00]98 if (rc != EOK)
99 return rc;
[3a7356dc]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 }
[78d3a00]106 }
[ad5c8a48]107
108 /* Check types and get values. */
[20e95be]109 /* Assigning 0 only to make the compiler happy. */
110 bithenge_int_t a_int = 0, b_int = 0;
[a42d7d8]111 bool a_bool = false, b_bool = false, out_bool = false;
[ad5c8a48]112 switch (self->op) {
113 case BITHENGE_EXPRESSION_ADD: /* fallthrough */
114 case BITHENGE_EXPRESSION_SUBTRACT: /* fallthrough */
[0153c87]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:
[ad5c8a48]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;
[2988aec7]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;
[ad5c8a48]144 default:
145 break;
146 }
147
[78d3a00]148 switch (self->op) {
[ad5c8a48]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;
[0153c87]158 case BITHENGE_EXPRESSION_INTEGER_DIVIDE:
[7c3fb9b]159 /*
160 * Integer division can behave in three major ways when the
161 * operands are signed: truncated, floored, or Euclidean. When
[0153c87]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
[7c3fb9b]165 * references.
166 */
[0153c87]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;
[78d3a00]195 case BITHENGE_EXPRESSION_EQUALS:
[a42d7d8]196 rc = bithenge_node_equal(&out_bool, a, b);
197 if (rc != EOK)
198 break;
199 rc = bithenge_new_boolean_node(out, out_bool);
[78d3a00]200 break;
[0153c87]201 case BITHENGE_EXPRESSION_NOT_EQUALS:
[a42d7d8]202 rc = bithenge_node_equal(&out_bool, a, b);
203 if (rc != EOK)
204 break;
205 rc = bithenge_new_boolean_node(out, !out_bool);
[2988aec7]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:
[3a7356dc]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);
[2988aec7]222 a = NULL;
223 b = NULL;
[78d3a00]224 break;
[ad5c8a48]225 case BITHENGE_EXPRESSION_INVALID_BINARY_OP:
226 assert(false);
227 break;
[78d3a00]228 }
[ad5c8a48]229
230error:
[78d3a00]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.
[7c3fb9b]254 * @return EOK on success or an error code from errno.h.
255 */
[b7fd2a0]256errno_t bithenge_binary_expression(bithenge_expression_t **out,
[78d3a00]257 bithenge_binary_op_t op, bithenge_expression_t *a,
258 bithenge_expression_t *b)
259{
[b7fd2a0]260 errno_t rc;
[78d3a00]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
[d1582b50]285/*
286 * in_node_expression
287 */
[a66ea217]288
[b7fd2a0]289static errno_t in_node_evaluate(bithenge_expression_t *self,
[a66ea217]290 bithenge_scope_t *scope, bithenge_node_t **out)
291{
[c9797067]292 for (; scope; scope = bithenge_scope_outer(scope)) {
[a66ea217]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.
[7c3fb9b]311 * @return EOK on success or an error code from errno.h.
312 */
[b7fd2a0]313errno_t bithenge_in_node_expression(bithenge_expression_t **out)
[a66ea217]314{
[1a3b953]315 if (bithenge_should_fail())
316 return ENOMEM;
[a66ea217]317 bithenge_expression_inc_ref(&in_node_expression);
318 *out = &in_node_expression;
319 return EOK;
320}
321
[d1582b50]322/*
323 * current_node_expression
324 */
[a66ea217]325
[b7fd2a0]326static errno_t current_node_evaluate(bithenge_expression_t *self,
[f85ca3f]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.
[7c3fb9b]346 * @return EOK on success or an error code from errno.h.
347 */
[b7fd2a0]348errno_t bithenge_current_node_expression(bithenge_expression_t **out)
[f85ca3f]349{
350 bithenge_expression_inc_ref(&current_node_expression);
351 *out = &current_node_expression;
352 return EOK;
353}
354
[d1582b50]355/*
356 * param_expression
357 */
[a66ea217]358
[6e34bd0]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
[b7fd2a0]376static errno_t param_expression_evaluate(bithenge_expression_t *base,
[6e34bd0]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.
[7c3fb9b]397 * @return EOK on success or an error code from errno.h.
398 */
[b7fd2a0]399errno_t bithenge_param_expression(bithenge_expression_t **out, int index)
[6e34bd0]400{
[b7fd2a0]401 errno_t rc;
[6e34bd0]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
[d1582b50]418/*
419 * const_expression
420 */
[a66ea217]421
[6e34bd0]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
[b7fd2a0]439static errno_t const_expression_evaluate(bithenge_expression_t *base,
[6e34bd0]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.
[7c3fb9b]463 * @return EOK on success or an error code from errno.h.
464 */
[b7fd2a0]465errno_t bithenge_const_expression(bithenge_expression_t **out,
[6e34bd0]466 bithenge_node_t *node)
467{
[b7fd2a0]468 errno_t rc;
[6e34bd0]469 const_expression_t *self = malloc(sizeof(*self));
[3f2ea63]470 if (!self) {
471 rc = ENOMEM;
472 goto error;
473 }
[6e34bd0]474
475 rc = bithenge_init_expression(const_as_expression(self),
476 &const_expression_ops);
[3f2ea63]477 if (rc != EOK)
478 goto error;
[6e34bd0]479
480 self->node = node;
481 *out = const_as_expression(self);
482 return EOK;
[3f2ea63]483
484error:
485 free(self);
486 bithenge_node_dec_ref(node);
487 return rc;
[6e34bd0]488}
489
[d1582b50]490/*
491 * scope_member_expression
492 */
[c12b2ae]493
[f85ca3f]494typedef struct {
495 bithenge_expression_t base;
496 bithenge_node_t *key;
[c12b2ae]497} scope_member_expression_t;
[f85ca3f]498
[c12b2ae]499static scope_member_expression_t *expression_as_scope_member(
500 bithenge_expression_t *base)
[f85ca3f]501{
[c12b2ae]502 return (scope_member_expression_t *)base;
[f85ca3f]503}
504
[c12b2ae]505static bithenge_expression_t *scope_member_as_expression(
506 scope_member_expression_t *expr)
[f85ca3f]507{
508 return &expr->base;
509}
510
[1b20da0]511static errno_t scope_member_expression_evaluate(bithenge_expression_t *base,
[f85ca3f]512 bithenge_scope_t *scope, bithenge_node_t **out)
513{
[c12b2ae]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);
[0153c87]518 if (!cur)
519 continue;
520 bithenge_node_inc_ref(self->key);
[b7fd2a0]521 errno_t rc = bithenge_node_get(cur, self->key, out);
[c12b2ae]522 bithenge_node_dec_ref(cur);
523 if (rc != ENOENT) /* EOK or error */
524 return rc;
525 }
[6be4142]526 return bithenge_scope_error(scope, "No scope member %t", self->key);
[f85ca3f]527}
528
[c12b2ae]529static void scope_member_expression_destroy(bithenge_expression_t *base)
[f85ca3f]530{
[c12b2ae]531 scope_member_expression_t *self = expression_as_scope_member(base);
[f85ca3f]532 bithenge_node_dec_ref(self->key);
533 free(self);
534}
535
[c12b2ae]536static const bithenge_expression_ops_t scope_member_expression_ops = {
537 .evaluate = scope_member_expression_evaluate,
538 .destroy = scope_member_expression_destroy,
[f85ca3f]539};
540
[0784869]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.
[f85ca3f]544 * @param[out] out Holds the new expression.
[0784869]545 * @param key The key to search for in nodes being created.
[7c3fb9b]546 * @return EOK on success or an error code from errno.h.
547 */
[b7fd2a0]548errno_t bithenge_scope_member_expression(bithenge_expression_t **out,
[c12b2ae]549 bithenge_node_t *key)
[f85ca3f]550{
[b7fd2a0]551 errno_t rc;
[c12b2ae]552 scope_member_expression_t *self = malloc(sizeof(*self));
[f85ca3f]553 if (!self) {
554 rc = ENOMEM;
555 goto error;
556 }
557
[c12b2ae]558 rc = bithenge_init_expression(scope_member_as_expression(self),
559 &scope_member_expression_ops);
[f85ca3f]560 if (rc != EOK)
561 goto error;
562
563 self->key = key;
[c12b2ae]564 *out = scope_member_as_expression(self);
[f85ca3f]565 return EOK;
566
567error:
568 bithenge_node_dec_ref(key);
569 free(self);
570 return rc;
571}
572
[d1582b50]573/*
574 * subblob_expression
575 */
[c12b2ae]576
577typedef struct {
578 bithenge_expression_t base;
[0b60d2d]579 bithenge_expression_t *blob, *start, *limit;
580 bool absolute_limit;
581} subblob_expression_t;
[c12b2ae]582
[0b60d2d]583static subblob_expression_t *expression_as_subblob(bithenge_expression_t *base)
[c12b2ae]584{
[0b60d2d]585 return (subblob_expression_t *)base;
[c12b2ae]586}
587
[0b60d2d]588static bithenge_expression_t *subblob_as_expression(subblob_expression_t *expr)
[c12b2ae]589{
590 return &expr->base;
591}
592
[1b20da0]593static errno_t subblob_expression_evaluate(bithenge_expression_t *base,
[c12b2ae]594 bithenge_scope_t *scope, bithenge_node_t **out)
595{
[0b60d2d]596 subblob_expression_t *self = expression_as_subblob(base);
597 bithenge_node_t *start_node;
[b7fd2a0]598 errno_t rc = bithenge_expression_evaluate(self->start, scope, &start_node);
[0b60d2d]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)
[c12b2ae]614 return rc;
[0b60d2d]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;
[c12b2ae]635 }
[0b60d2d]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);
[c12b2ae]643}
644
[0b60d2d]645static void subblob_expression_destroy(bithenge_expression_t *base)
[c12b2ae]646{
[0b60d2d]647 subblob_expression_t *self = expression_as_subblob(base);
[c9797067]648 bithenge_expression_dec_ref(self->blob);
[0b60d2d]649 bithenge_expression_dec_ref(self->start);
650 bithenge_expression_dec_ref(self->limit);
[c12b2ae]651 free(self);
652}
653
[0b60d2d]654static const bithenge_expression_ops_t subblob_expression_ops = {
655 .evaluate = subblob_expression_evaluate,
656 .destroy = subblob_expression_destroy,
[c12b2ae]657};
658
[0b60d2d]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.
[7c3fb9b]668 * @return EOK on success or an error code from errno.h.
669 */
[b7fd2a0]670errno_t bithenge_subblob_expression(bithenge_expression_t **out,
[0b60d2d]671 bithenge_expression_t *blob, bithenge_expression_t *start,
672 bithenge_expression_t *limit, bool absolute_limit)
[c12b2ae]673{
[b7fd2a0]674 errno_t rc;
[0b60d2d]675 subblob_expression_t *self = malloc(sizeof(*self));
[c12b2ae]676 if (!self) {
677 rc = ENOMEM;
678 goto error;
679 }
680
[0b60d2d]681 rc = bithenge_init_expression(subblob_as_expression(self),
682 &subblob_expression_ops);
[c12b2ae]683 if (rc != EOK)
684 goto error;
685
[0b60d2d]686 self->blob = blob;
687 self->start = start;
688 self->limit = limit;
689 self->absolute_limit = absolute_limit;
690 *out = subblob_as_expression(self);
[c12b2ae]691 return EOK;
692
693error:
[0b60d2d]694 bithenge_expression_dec_ref(blob);
695 bithenge_expression_dec_ref(start);
696 bithenge_expression_dec_ref(limit);
[c12b2ae]697 free(self);
698 return rc;
699}
700
[d1582b50]701/*
702 * param_wrapper
703 */
[c12b2ae]704
[6e34bd0]705typedef struct {
706 bithenge_transform_t base;
707 bithenge_transform_t *transform;
708 bithenge_expression_t **params;
709} param_wrapper_t;
710
711static inline bithenge_transform_t *param_wrapper_as_transform(
712 param_wrapper_t *self)
713{
714 return &self->base;
715}
716
717static inline param_wrapper_t *transform_as_param_wrapper(
718 bithenge_transform_t *base)
719{
720 return (param_wrapper_t *)base;
721}
722
[b7fd2a0]723static errno_t param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
[6e34bd0]724 *inner, bithenge_scope_t *outer)
725{
[b7fd2a0]726 errno_t rc;
[6e34bd0]727 int num_params = bithenge_transform_num_params(self->transform);
728 rc = bithenge_scope_alloc_params(inner, num_params);
729 if (rc != EOK)
730 return rc;
731 for (int i = 0; i < num_params; i++) {
732 bithenge_node_t *node;
733 rc = bithenge_expression_evaluate(self->params[i], outer,
734 &node);
735 if (rc != EOK)
736 return rc;
737 rc = bithenge_scope_set_param(inner, i, node);
738 if (rc != EOK)
739 return rc;
740 }
741 return EOK;
742}
743
[b7fd2a0]744static errno_t param_wrapper_apply(bithenge_transform_t *base,
[6e34bd0]745 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
746{
747 param_wrapper_t *self = transform_as_param_wrapper(base);
[f9c314a5]748 bithenge_scope_t *inner;
[b7fd2a0]749 errno_t rc = bithenge_scope_new(&inner, outer);
[f9c314a5]750 if (rc != EOK)
751 return rc;
752 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]753 if (rc != EOK)
754 goto error;
755
[f9c314a5]756 rc = bithenge_transform_apply(self->transform, inner, in, out);
[6e34bd0]757 in = NULL;
758
759error:
[f9c314a5]760 bithenge_scope_dec_ref(inner);
[6e34bd0]761 return rc;
762}
763
[b7fd2a0]764static errno_t param_wrapper_prefix_length(bithenge_transform_t *base,
[6e34bd0]765 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
766{
767 param_wrapper_t *self = transform_as_param_wrapper(base);
[f9c314a5]768 bithenge_scope_t *inner;
[b7fd2a0]769 errno_t rc = bithenge_scope_new(&inner, outer);
[f9c314a5]770 if (rc != EOK)
771 return rc;
772 rc = param_wrapper_fill_scope(self, inner, outer);
[6e34bd0]773 if (rc != EOK)
774 goto error;
775
[f9c314a5]776 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
[6e34bd0]777 in = NULL;
778
779error:
[f9c314a5]780 bithenge_scope_dec_ref(inner);
[6e34bd0]781 return rc;
782}
[4056ad0]783
[b7fd2a0]784static errno_t param_wrapper_prefix_apply(bithenge_transform_t *base,
[0191bd3]785 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
786 aoff64_t *out_length)
787{
788 param_wrapper_t *self = transform_as_param_wrapper(base);
789 bithenge_scope_t *inner;
[b7fd2a0]790 errno_t rc = bithenge_scope_new(&inner, outer);
[0191bd3]791 if (rc != EOK)
792 return rc;
793 rc = param_wrapper_fill_scope(self, inner, outer);
794 if (rc != EOK)
795 goto error;
796
797 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
798 out_node, out_length);
799
800error:
801 bithenge_scope_dec_ref(inner);
802 return rc;
803}
804
[6e34bd0]805static void param_wrapper_destroy(bithenge_transform_t *base)
806{
807 param_wrapper_t *self = transform_as_param_wrapper(base);
808 int num_params = bithenge_transform_num_params(self->transform);
809 bithenge_transform_dec_ref(self->transform);
810 for (int i = 0; i < num_params; i++)
811 bithenge_expression_dec_ref(self->params[i]);
812 free(self->params);
813 free(self);
814}
815
816static const bithenge_transform_ops_t param_wrapper_ops = {
817 .apply = param_wrapper_apply,
818 .prefix_length = param_wrapper_prefix_length,
[0191bd3]819 .prefix_apply = param_wrapper_prefix_apply,
[6e34bd0]820 .destroy = param_wrapper_destroy,
821};
822
823/** Create a transform that calculates parameters for another transform. Takes
824 * ownership of @a transform, @a params, and each element of @a params. The
825 * number of parameters must be correct.
826 * @param[out] out Holds the new transform.
827 * @param transform The transform for which parameters are calculated.
828 * @param params The expressions used to calculate the parameters.
[7c3fb9b]829 * @return EOK on success or an error code from errno.h.
830 */
[b7fd2a0]831errno_t bithenge_param_wrapper(bithenge_transform_t **out,
[6e34bd0]832 bithenge_transform_t *transform, bithenge_expression_t **params)
833{
[b7fd2a0]834 errno_t rc;
[6e34bd0]835 int num_params = bithenge_transform_num_params(transform);
836 param_wrapper_t *self = malloc(sizeof(*self));
837 if (!self) {
838 rc = ENOMEM;
839 goto error;
840 }
841
842 rc = bithenge_init_transform(param_wrapper_as_transform(self),
[03cad47]843 &param_wrapper_ops, 0);
[6e34bd0]844 if (rc != EOK)
845 goto error;
846
847 self->transform = transform;
848 self->params = params;
849 *out = param_wrapper_as_transform(self);
850 return EOK;
851
852error:
853 free(self);
854 for (int i = 0; i < num_params; i++)
855 bithenge_expression_dec_ref(params[i]);
856 free(params);
857 bithenge_transform_dec_ref(transform);
858 return rc;
859}
860
[d1582b50]861/*
862 * expression_transform
863 */
[a66ea217]864
865/* Also used by inputless_transform. */
[20ac1a4]866typedef struct {
867 bithenge_transform_t base;
868 bithenge_expression_t *expr;
869} expression_transform_t;
870
871static inline bithenge_transform_t *expression_as_transform(
872 expression_transform_t *self)
873{
874 return &self->base;
875}
876
877static inline expression_transform_t *transform_as_expression(
878 bithenge_transform_t *base)
879{
880 return (expression_transform_t *)base;
881}
882
[b7fd2a0]883static errno_t expression_transform_apply(bithenge_transform_t *base,
[20ac1a4]884 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
885{
886 expression_transform_t *self = transform_as_expression(base);
[a66ea217]887 bithenge_scope_t *inner;
[b7fd2a0]888 errno_t rc = bithenge_scope_new(&inner, scope);
[20ac1a4]889 if (rc != EOK)
890 return rc;
[a66ea217]891 bithenge_scope_set_in_node(inner, in);
892 rc = bithenge_expression_evaluate(self->expr, inner, out);
893 bithenge_scope_dec_ref(inner);
894 return rc;
895}
896
897/* Also used by inputless_transform. */
898static void expression_transform_destroy(bithenge_transform_t *base)
899{
900 expression_transform_t *self = transform_as_expression(base);
901 bithenge_expression_dec_ref(self->expr);
902 free(self);
[20ac1a4]903}
904
[a66ea217]905static const bithenge_transform_ops_t expression_transform_ops = {
906 .apply = expression_transform_apply,
907 .destroy = expression_transform_destroy,
908};
909
910/** Create a transform that evaluates an expression on the input node. Takes a
911 * reference to the expression.
912 * @param[out] out Holds the new transform.
913 * @param expr The expression to evaluate.
[7c3fb9b]914 * @return EOK on success or an error code from errno.h.
915 */
[1433ecda]916errno_t bithenge_expression_transform(bithenge_transform_t **out,
[a66ea217]917 bithenge_expression_t *expr)
918{
[b7fd2a0]919 errno_t rc;
[a66ea217]920 expression_transform_t *self = malloc(sizeof(*self));
921 if (!self) {
922 rc = ENOMEM;
923 goto error;
924 }
925
926 rc = bithenge_init_transform(expression_as_transform(self),
927 &expression_transform_ops, 0);
928 if (rc != EOK)
929 goto error;
930
931 self->expr = expr;
932 *out = expression_as_transform(self);
933 return EOK;
934
935error:
936 free(self);
937 bithenge_expression_dec_ref(expr);
938 return rc;
939}
940
[d1582b50]941/*
942 * inputless_transform
943 */
[a66ea217]944
[b7fd2a0]945static errno_t inputless_transform_prefix_length(bithenge_transform_t *base,
[20ac1a4]946 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
947{
948 *out = 0;
949 return EOK;
950}
951
[b7fd2a0]952static errno_t inputless_transform_prefix_apply(bithenge_transform_t *base,
[a66ea217]953 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
954 aoff64_t *out_size)
[20ac1a4]955{
956 expression_transform_t *self = transform_as_expression(base);
[1b6b76d]957 if (out_size)
958 *out_size = 0;
[a66ea217]959 return bithenge_expression_evaluate(self->expr, scope, out_node);
[20ac1a4]960}
961
[a66ea217]962static const bithenge_transform_ops_t inputless_transform_ops = {
963 .prefix_length = inputless_transform_prefix_length,
964 .prefix_apply = inputless_transform_prefix_apply,
[20ac1a4]965 .destroy = expression_transform_destroy,
966};
967
968/** Create a transform that takes an empty blob and produces the result of an
969 * expression. Takes a reference to the expression.
970 * @param[out] out Holds the new transform.
971 * @param expr The expression to evaluate.
[7c3fb9b]972 * @return EOK on success or an error code from errno.h.
973 */
[1433ecda]974errno_t bithenge_inputless_transform(bithenge_transform_t **out,
[20ac1a4]975 bithenge_expression_t *expr)
976{
[b7fd2a0]977 errno_t rc;
[20ac1a4]978 expression_transform_t *self = malloc(sizeof(*self));
979 if (!self) {
980 rc = ENOMEM;
981 goto error;
982 }
983
984 rc = bithenge_init_transform(expression_as_transform(self),
[a66ea217]985 &inputless_transform_ops, 0);
[20ac1a4]986 if (rc != EOK)
987 goto error;
988
989 self->expr = expr;
990 *out = expression_as_transform(self);
991 return EOK;
992
993error:
994 free(self);
995 bithenge_expression_dec_ref(expr);
996 return rc;
997}
998
[d1582b50]999/*
1000 * concat_blob
1001 */
[a66ea217]1002
[10334c2e]1003typedef struct {
[3a7356dc]1004 bithenge_blob_t base;
1005 bithenge_blob_t *a, *b;
1006 aoff64_t a_size;
1007 bithenge_expression_t *b_expr;
1008 bithenge_scope_t *scope;
1009} concat_blob_t;
1010
1011static inline concat_blob_t *blob_as_concat(bithenge_blob_t *base)
[10334c2e]1012{
[3a7356dc]1013 return (concat_blob_t *)base;
[10334c2e]1014}
1015
[3a7356dc]1016static inline bithenge_blob_t *concat_as_blob(concat_blob_t *blob)
[10334c2e]1017{
[3a7356dc]1018 return &blob->base;
[10334c2e]1019}
1020
[b7fd2a0]1021static errno_t concat_blob_evaluate_b(concat_blob_t *self)
[10334c2e]1022{
[3a7356dc]1023 if (self->b)
1024 return EOK;
1025 bithenge_node_t *b_node;
[b7fd2a0]1026 errno_t rc = bithenge_expression_evaluate(self->b_expr, self->scope,
[3a7356dc]1027 &b_node);
[10334c2e]1028 if (rc != EOK)
1029 return rc;
[3a7356dc]1030 if (bithenge_node_type(b_node) != BITHENGE_NODE_BLOB) {
1031 bithenge_node_dec_ref(b_node);
1032 return bithenge_scope_error(self->scope,
1033 "Concatenation arguments must be blobs");
[10334c2e]1034 }
[3a7356dc]1035 self->b = bithenge_node_as_blob(b_node);
1036 bithenge_expression_dec_ref(self->b_expr);
1037 bithenge_scope_dec_ref(self->scope);
1038 self->b_expr = NULL;
1039 self->scope = NULL;
[10334c2e]1040 return EOK;
1041}
1042
[b7fd2a0]1043static errno_t concat_blob_size(bithenge_blob_t *base, aoff64_t *size)
[10334c2e]1044{
[3a7356dc]1045 concat_blob_t *self = blob_as_concat(base);
[b7fd2a0]1046 errno_t rc = concat_blob_evaluate_b(self);
[10334c2e]1047 if (rc != EOK)
1048 return rc;
[3a7356dc]1049 rc = bithenge_blob_size(self->b, size);
1050 *size += self->a_size;
1051 return rc;
[10334c2e]1052}
1053
[b7fd2a0]1054static errno_t concat_blob_read(bithenge_blob_t *base, aoff64_t offset,
[3a7356dc]1055 char *buffer, aoff64_t *size)
[10334c2e]1056{
[b7fd2a0]1057 errno_t rc;
[3a7356dc]1058 concat_blob_t *self = blob_as_concat(base);
1059
1060 aoff64_t a_size = 0, b_size = 0;
1061 if (offset < self->a_size) {
1062 a_size = *size;
1063 rc = bithenge_blob_read(self->a, offset, buffer, &a_size);
1064 if (rc != EOK)
1065 return rc;
1066 }
1067 if (offset + *size > self->a_size) {
1068 rc = concat_blob_evaluate_b(self);
1069 if (rc != EOK)
1070 return rc;
1071 b_size = *size - a_size;
1072 rc = bithenge_blob_read(self->b,
1073 offset + a_size - self->a_size, buffer + a_size, &b_size);
1074 if (rc != EOK)
1075 return rc;
1076 }
1077 assert(a_size + b_size <= *size);
1078 *size = a_size + b_size;
1079 return EOK;
[10334c2e]1080}
1081
[b7fd2a0]1082static errno_t concat_blob_read_bits(bithenge_blob_t *base, aoff64_t offset,
[3a7356dc]1083 char *buffer, aoff64_t *size, bool little_endian)
[10334c2e]1084{
[b7fd2a0]1085 errno_t rc;
[3a7356dc]1086 concat_blob_t *self = blob_as_concat(base);
1087
1088 aoff64_t a_size = 0, b_size = 0;
1089 if (offset < self->a_size) {
1090 a_size = *size;
1091 rc = bithenge_blob_read_bits(self->a, offset, buffer, &a_size,
1092 little_endian);
1093 if (rc != EOK)
1094 return rc;
1095 }
1096 if (offset + *size > self->a_size) {
1097 rc = concat_blob_evaluate_b(self);
1098 if (rc != EOK)
1099 return rc;
[1c79996]1100 b_size = *size - a_size;
1101 assert(a_size % 8 == 0); /* TODO: don't require this */
[3a7356dc]1102 rc = bithenge_blob_read_bits(self->b,
[1c79996]1103 offset + a_size - self->a_size, buffer + a_size / 8,
1104 &b_size, little_endian);
[3a7356dc]1105 if (rc != EOK)
1106 return rc;
1107 }
1108 assert(a_size + b_size <= *size);
1109 *size = a_size + b_size;
1110 return EOK;
1111}
1112
1113static void concat_blob_destroy(bithenge_blob_t *base)
1114{
1115 concat_blob_t *self = blob_as_concat(base);
1116 bithenge_blob_dec_ref(self->a);
1117 bithenge_blob_dec_ref(self->b);
1118 bithenge_expression_dec_ref(self->b_expr);
1119 bithenge_scope_dec_ref(self->scope);
[10334c2e]1120 free(self);
1121}
1122
[3a7356dc]1123static const bithenge_random_access_blob_ops_t concat_blob_ops = {
1124 .size = concat_blob_size,
1125 .read = concat_blob_read,
1126 .read_bits = concat_blob_read_bits,
1127 .destroy = concat_blob_destroy,
[10334c2e]1128};
1129
[3a7356dc]1130/** Create a concatenated blob. Takes references to @a a and @a b.
1131 * @param[out] out Holds the new blob.
1132 * @param a The first blob.
1133 * @param b The second blob.
[7c3fb9b]1134 * @return EOK on success or an error code from errno.h.
1135 */
[b7fd2a0]1136errno_t bithenge_concat_blob(bithenge_node_t **out, bithenge_blob_t *a,
[3a7356dc]1137 bithenge_blob_t *b)
[10334c2e]1138{
[3a7356dc]1139 assert(out);
1140 assert(a);
1141 assert(b);
[b7fd2a0]1142 errno_t rc;
[3a7356dc]1143 concat_blob_t *self = malloc(sizeof(*self));
[10334c2e]1144 if (!self) {
1145 rc = ENOMEM;
1146 goto error;
1147 }
1148
[3a7356dc]1149 rc = bithenge_blob_size(a, &self->a_size);
[10334c2e]1150 if (rc != EOK)
1151 goto error;
1152
[3a7356dc]1153 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1154 &concat_blob_ops);
1155 if (rc != EOK)
1156 goto error;
1157 self->a = a;
1158 self->b = b;
1159 self->b_expr = NULL;
1160 self->scope = NULL;
1161 *out = bithenge_blob_as_node(concat_as_blob(self));
[10334c2e]1162 return EOK;
1163
1164error:
[3a7356dc]1165 bithenge_blob_dec_ref(a);
1166 bithenge_blob_dec_ref(b);
1167 free(self);
1168 return rc;
1169}
1170
1171/** Create a lazy concatenated blob. Takes references to @a a, @a b_expr, and
1172 * @a scope.
1173 * @param[out] out Holds the new blob.
1174 * @param a The first blob.
1175 * @param b_expr An expression to calculate the second blob.
1176 * @param scope The scope in which @a b_expr should be evaluated.
[7c3fb9b]1177 * @return EOK on success or an error code from errno.h.
1178 */
[b7fd2a0]1179errno_t bithenge_concat_blob_lazy(bithenge_node_t **out, bithenge_blob_t *a,
[3a7356dc]1180 bithenge_expression_t *b_expr, bithenge_scope_t *scope)
1181{
1182 assert(out);
1183 assert(a);
1184 assert(b_expr);
1185 assert(scope);
[b7fd2a0]1186 errno_t rc;
[3a7356dc]1187 concat_blob_t *self = malloc(sizeof(*self));
1188 if (!self) {
1189 rc = ENOMEM;
1190 goto error;
1191 }
1192
1193 rc = bithenge_blob_size(a, &self->a_size);
1194 if (rc != EOK)
1195 goto error;
1196
1197 rc = bithenge_init_random_access_blob(concat_as_blob(self),
1198 &concat_blob_ops);
1199 if (rc != EOK)
1200 goto error;
1201 self->a = a;
1202 self->b = NULL;
1203 self->b_expr = b_expr;
1204 self->scope = scope;
1205 *out = bithenge_blob_as_node(concat_as_blob(self));
1206 return EOK;
1207
1208error:
1209 bithenge_blob_dec_ref(a);
1210 bithenge_expression_dec_ref(b_expr);
1211 bithenge_scope_dec_ref(scope);
[10334c2e]1212 free(self);
1213 return rc;
1214}
1215
[6e34bd0]1216/** @}
1217 */
Note: See TracBrowser for help on using the repository browser.