source: mainline/uspace/app/bithenge/expression.c@ a8be91a

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

Bithenge: keep track of outer scopes and find parameters there

  • Property mode set to 100644
File size: 19.2 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Expressions.
35 */
36
37#include <assert.h>
38#include <errno.h>
39#include <stdlib.h>
40#include "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
60static void expression_indestructible(bithenge_expression_t *self)
61{
62 assert(false);
63}
64
65typedef struct {
66 bithenge_expression_t base;
67 bithenge_binary_op_t op;
68 bithenge_expression_t *a, *b;
69} binary_expression_t;
70
71static inline binary_expression_t *expression_as_binary(
72 bithenge_expression_t *base)
73{
74 return (binary_expression_t *)base;
75}
76
77static inline bithenge_expression_t *binary_as_expression(
78 binary_expression_t *self)
79{
80 return &self->base;
81}
82
83static int binary_expression_evaluate(bithenge_expression_t *base,
84 bithenge_scope_t *scope, bithenge_node_t **out)
85{
86 binary_expression_t *self = expression_as_binary(base);
87 bithenge_node_t *a, *b;
88 int rc = bithenge_expression_evaluate(self->a, scope, &a);
89 if (rc != EOK)
90 return rc;
91 rc = bithenge_expression_evaluate(self->b, scope, &b);
92 if (rc != EOK) {
93 bithenge_node_dec_ref(a);
94 return rc;
95 }
96 switch (self->op) {
97 case BITHENGE_EXPRESSION_EQUALS:
98 rc = bithenge_new_boolean_node(out, bithenge_node_equal(a, b));
99 break;
100 }
101 bithenge_node_dec_ref(a);
102 bithenge_node_dec_ref(b);
103 return rc;
104}
105
106static void binary_expression_destroy(bithenge_expression_t *base)
107{
108 binary_expression_t *self = expression_as_binary(base);
109 bithenge_expression_dec_ref(self->a);
110 bithenge_expression_dec_ref(self->b);
111 free(self);
112}
113
114static const bithenge_expression_ops_t binary_expression_ops = {
115 .evaluate = binary_expression_evaluate,
116 .destroy = binary_expression_destroy,
117};
118
119/** Create a binary expression. Takes ownership of @a a and @a b.
120 * @param[out] out Holds the new expression.
121 * @param op The operator to apply.
122 * @param a The first operand.
123 * @param b The second operand.
124 * @return EOK on success or an error code from errno.h. */
125int bithenge_binary_expression(bithenge_expression_t **out,
126 bithenge_binary_op_t op, bithenge_expression_t *a,
127 bithenge_expression_t *b)
128{
129 int rc;
130 binary_expression_t *self = malloc(sizeof(*self));
131 if (!self) {
132 rc = ENOMEM;
133 goto error;
134 }
135
136 rc = bithenge_init_expression(binary_as_expression(self),
137 &binary_expression_ops);
138 if (rc != EOK)
139 goto error;
140
141 self->op = op;
142 self->a = a;
143 self->b = b;
144 *out = binary_as_expression(self);
145 return EOK;
146
147error:
148 bithenge_expression_dec_ref(a);
149 bithenge_expression_dec_ref(b);
150 free(self);
151 return rc;
152}
153
154static int current_node_evaluate(bithenge_expression_t *self,
155 bithenge_scope_t *scope, bithenge_node_t **out)
156{
157 *out = bithenge_scope_get_current_node(scope);
158 if (!*out)
159 return EINVAL;
160 return EOK;
161}
162
163static const bithenge_expression_ops_t current_node_ops = {
164 .evaluate = current_node_evaluate,
165 .destroy = expression_indestructible,
166};
167
168static bithenge_expression_t current_node_expression = {
169 &current_node_ops, 1
170};
171
172/** Create an expression that gets the current node being created.
173 * @param[out] out Holds the new expression.
174 * @return EOK on success or an error code from errno.h. */
175int bithenge_current_node_expression(bithenge_expression_t **out)
176{
177 bithenge_expression_inc_ref(&current_node_expression);
178 *out = &current_node_expression;
179 return EOK;
180}
181
182typedef struct {
183 bithenge_expression_t base;
184 int index;
185} param_expression_t;
186
187static inline param_expression_t *expression_as_param(
188 bithenge_expression_t *base)
189{
190 return (param_expression_t *)base;
191}
192
193static inline bithenge_expression_t *param_as_expression(
194 param_expression_t *self)
195{
196 return &self->base;
197}
198
199static int param_expression_evaluate(bithenge_expression_t *base,
200 bithenge_scope_t *scope, bithenge_node_t **out)
201{
202 param_expression_t *self = expression_as_param(base);
203 return bithenge_scope_get_param(scope, self->index, out);
204}
205
206static void param_expression_destroy(bithenge_expression_t *base)
207{
208 param_expression_t *self = expression_as_param(base);
209 free(self);
210}
211
212static const bithenge_expression_ops_t param_expression_ops = {
213 .evaluate = param_expression_evaluate,
214 .destroy = param_expression_destroy,
215};
216
217/** Create an expression that returns a parameter.
218 * @param[out] out Holds the created expression.
219 * @param index The index of the parameter to get.
220 * @return EOK on success or an error code from errno.h. */
221int bithenge_param_expression(bithenge_expression_t **out, int index)
222{
223 int rc;
224 param_expression_t *self = malloc(sizeof(*self));
225 if (!self)
226 return ENOMEM;
227
228 rc = bithenge_init_expression(param_as_expression(self),
229 &param_expression_ops);
230 if (rc != EOK) {
231 free(self);
232 return rc;
233 }
234
235 self->index = index;
236 *out = param_as_expression(self);
237 return EOK;
238}
239
240typedef struct {
241 bithenge_expression_t base;
242 bithenge_node_t *node;
243} const_expression_t;
244
245static inline const_expression_t *expression_as_const(
246 bithenge_expression_t *base)
247{
248 return (const_expression_t *)base;
249}
250
251static inline bithenge_expression_t *const_as_expression(
252 const_expression_t *self)
253{
254 return &self->base;
255}
256
257static int const_expression_evaluate(bithenge_expression_t *base,
258 bithenge_scope_t *scope, bithenge_node_t **out)
259{
260 const_expression_t *self = expression_as_const(base);
261 bithenge_node_inc_ref(self->node);
262 *out = self->node;
263 return EOK;
264}
265
266static void const_expression_destroy(bithenge_expression_t *base)
267{
268 const_expression_t *self = expression_as_const(base);
269 bithenge_node_dec_ref(self->node);
270 free(self);
271}
272
273static const bithenge_expression_ops_t const_expression_ops = {
274 .evaluate = const_expression_evaluate,
275 .destroy = const_expression_destroy,
276};
277
278/** Create an expression that returns a constant. Takes a reference to @a node.
279 * @param[out] out Holds the created expression.
280 * @param node The constant.
281 * @return EOK on success or an error code from errno.h. */
282int bithenge_const_expression(bithenge_expression_t **out,
283 bithenge_node_t *node)
284{
285 int rc;
286 const_expression_t *self = malloc(sizeof(*self));
287 if (!self) {
288 rc = ENOMEM;
289 goto error;
290 }
291
292 rc = bithenge_init_expression(const_as_expression(self),
293 &const_expression_ops);
294 if (rc != EOK)
295 goto error;
296
297 self->node = node;
298 *out = const_as_expression(self);
299 return EOK;
300
301error:
302 free(self);
303 bithenge_node_dec_ref(node);
304 return rc;
305}
306
307typedef struct {
308 bithenge_expression_t base;
309 bithenge_expression_t *expr;
310 bithenge_node_t *key;
311} member_expression_t;
312
313static member_expression_t *expression_as_member(bithenge_expression_t *base)
314{
315 return (member_expression_t *)base;
316}
317
318static bithenge_expression_t *member_as_expression(member_expression_t *expr)
319{
320 return &expr->base;
321}
322
323static int member_expression_evaluate(bithenge_expression_t *base,
324 bithenge_scope_t *scope, bithenge_node_t **out)
325{
326 member_expression_t *self = expression_as_member(base);
327 bithenge_node_t *node;
328 int rc = bithenge_expression_evaluate(self->expr, scope, &node);
329 if (rc != EOK)
330 return rc;
331 bithenge_node_inc_ref(self->key);
332 rc = bithenge_node_get(node, self->key, out);
333 bithenge_node_dec_ref(node);
334 return rc;
335}
336
337static void member_expression_destroy(bithenge_expression_t *base)
338{
339 member_expression_t *self = expression_as_member(base);
340 bithenge_expression_dec_ref(self->expr);
341 bithenge_node_dec_ref(self->key);
342 free(self);
343}
344
345static const bithenge_expression_ops_t member_expression_ops = {
346 .evaluate = member_expression_evaluate,
347 .destroy = member_expression_destroy,
348};
349
350/** Create an expression that gets a member from a node. Takes references to
351 * @a expr and @a key.
352 * @param[out] out Holds the new expression.
353 * @param expr Calculates the node to get the member of.
354 * @param key The member to get.
355 * @return EOK on success or an error code from errno.h. */
356int bithenge_member_expression(bithenge_expression_t **out,
357 bithenge_expression_t *expr, bithenge_node_t *key)
358{
359 int rc;
360 member_expression_t *self = malloc(sizeof(*self));
361 if (!self) {
362 rc = ENOMEM;
363 goto error;
364 }
365
366 rc = bithenge_init_expression(member_as_expression(self),
367 &member_expression_ops);
368 if (rc != EOK)
369 goto error;
370
371 self->expr = expr;
372 self->key = key;
373 *out = member_as_expression(self);
374 return EOK;
375
376error:
377 bithenge_expression_dec_ref(expr);
378 bithenge_node_dec_ref(key);
379 free(self);
380 return rc;
381}
382
383typedef struct {
384 bithenge_transform_t base;
385 bithenge_transform_t *transform;
386 bithenge_expression_t **params;
387} param_wrapper_t;
388
389static inline bithenge_transform_t *param_wrapper_as_transform(
390 param_wrapper_t *self)
391{
392 return &self->base;
393}
394
395static inline param_wrapper_t *transform_as_param_wrapper(
396 bithenge_transform_t *base)
397{
398 return (param_wrapper_t *)base;
399}
400
401static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
402 *inner, bithenge_scope_t *outer)
403{
404 int rc;
405 int num_params = bithenge_transform_num_params(self->transform);
406 rc = bithenge_scope_alloc_params(inner, num_params);
407 if (rc != EOK)
408 return rc;
409 for (int i = 0; i < num_params; i++) {
410 bithenge_node_t *node;
411 rc = bithenge_expression_evaluate(self->params[i], outer,
412 &node);
413 if (rc != EOK)
414 return rc;
415 rc = bithenge_scope_set_param(inner, i, node);
416 if (rc != EOK)
417 return rc;
418 }
419 return EOK;
420}
421
422static int param_wrapper_apply(bithenge_transform_t *base,
423 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
424{
425 param_wrapper_t *self = transform_as_param_wrapper(base);
426 bithenge_scope_t *inner;
427 int rc = bithenge_scope_new(&inner, outer);
428 if (rc != EOK)
429 return rc;
430 rc = param_wrapper_fill_scope(self, inner, outer);
431 if (rc != EOK)
432 goto error;
433
434 rc = bithenge_transform_apply(self->transform, inner, in, out);
435 in = NULL;
436
437error:
438 bithenge_scope_dec_ref(inner);
439 return rc;
440}
441
442static int param_wrapper_prefix_length(bithenge_transform_t *base,
443 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
444{
445 param_wrapper_t *self = transform_as_param_wrapper(base);
446 bithenge_scope_t *inner;
447 int rc = bithenge_scope_new(&inner, outer);
448 if (rc != EOK)
449 return rc;
450 rc = param_wrapper_fill_scope(self, inner, outer);
451 if (rc != EOK)
452 goto error;
453
454 rc = bithenge_transform_prefix_length(self->transform, inner, in, out);
455 in = NULL;
456
457error:
458 bithenge_scope_dec_ref(inner);
459 return rc;
460}
461
462static int param_wrapper_prefix_apply(bithenge_transform_t *base,
463 bithenge_scope_t *outer, bithenge_blob_t *in, bithenge_node_t **out_node,
464 aoff64_t *out_length)
465{
466 param_wrapper_t *self = transform_as_param_wrapper(base);
467 bithenge_scope_t *inner;
468 int rc = bithenge_scope_new(&inner, outer);
469 if (rc != EOK)
470 return rc;
471 rc = param_wrapper_fill_scope(self, inner, outer);
472 if (rc != EOK)
473 goto error;
474
475 rc = bithenge_transform_prefix_apply(self->transform, inner, in,
476 out_node, out_length);
477
478error:
479 bithenge_scope_dec_ref(inner);
480 return rc;
481}
482
483static void param_wrapper_destroy(bithenge_transform_t *base)
484{
485 param_wrapper_t *self = transform_as_param_wrapper(base);
486 int num_params = bithenge_transform_num_params(self->transform);
487 bithenge_transform_dec_ref(self->transform);
488 for (int i = 0; i < num_params; i++)
489 bithenge_expression_dec_ref(self->params[i]);
490 free(self->params);
491 free(self);
492}
493
494static const bithenge_transform_ops_t param_wrapper_ops = {
495 .apply = param_wrapper_apply,
496 .prefix_length = param_wrapper_prefix_length,
497 .prefix_apply = param_wrapper_prefix_apply,
498 .destroy = param_wrapper_destroy,
499};
500
501/** Create a transform that calculates parameters for another transform. Takes
502 * ownership of @a transform, @a params, and each element of @a params. The
503 * number of parameters must be correct.
504 * @param[out] out Holds the new transform.
505 * @param transform The transform for which parameters are calculated.
506 * @param params The expressions used to calculate the parameters.
507 * @return EOK on success or an error code from errno.h. */
508int bithenge_param_wrapper(bithenge_transform_t **out,
509 bithenge_transform_t *transform, bithenge_expression_t **params)
510{
511 int rc;
512 int num_params = bithenge_transform_num_params(transform);
513 param_wrapper_t *self = malloc(sizeof(*self));
514 if (!self) {
515 rc = ENOMEM;
516 goto error;
517 }
518
519 rc = bithenge_init_transform(param_wrapper_as_transform(self),
520 &param_wrapper_ops, 0);
521 if (rc != EOK)
522 goto error;
523
524 self->transform = transform;
525 self->params = params;
526 *out = param_wrapper_as_transform(self);
527 return EOK;
528
529error:
530 free(self);
531 for (int i = 0; i < num_params; i++)
532 bithenge_expression_dec_ref(params[i]);
533 free(params);
534 bithenge_transform_dec_ref(transform);
535 return rc;
536}
537
538typedef struct {
539 bithenge_transform_t base;
540 bithenge_expression_t *expr;
541} expression_transform_t;
542
543static inline bithenge_transform_t *expression_as_transform(
544 expression_transform_t *self)
545{
546 return &self->base;
547}
548
549static inline expression_transform_t *transform_as_expression(
550 bithenge_transform_t *base)
551{
552 return (expression_transform_t *)base;
553}
554
555static int expression_transform_apply(bithenge_transform_t *base,
556 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
557{
558 expression_transform_t *self = transform_as_expression(base);
559 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
560 return EINVAL;
561 aoff64_t len;
562 int rc = bithenge_blob_size(bithenge_node_as_blob(in), &len);
563 if (rc != EOK)
564 return rc;
565 if (len != 0)
566 return EINVAL;
567 return bithenge_expression_evaluate(self->expr, scope, out);
568}
569
570static int expression_transform_prefix_length(bithenge_transform_t *base,
571 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
572{
573 *out = 0;
574 return EOK;
575}
576
577static void expression_transform_destroy(bithenge_transform_t *base)
578{
579 expression_transform_t *self = transform_as_expression(base);
580 bithenge_expression_dec_ref(self->expr);
581 free(self);
582}
583
584static const bithenge_transform_ops_t expression_transform_ops = {
585 .apply = expression_transform_apply,
586 .prefix_length = expression_transform_prefix_length,
587 .destroy = expression_transform_destroy,
588};
589
590/** Create a transform that takes an empty blob and produces the result of an
591 * expression. Takes a reference to the expression.
592 * @param[out] out Holds the new transform.
593 * @param expr The expression to evaluate.
594 * @return EOK on success or an error code from errno.h. */
595int bithenge_expression_transform(bithenge_transform_t ** out,
596 bithenge_expression_t *expr)
597{
598 int rc;
599 expression_transform_t *self = malloc(sizeof(*self));
600 if (!self) {
601 rc = ENOMEM;
602 goto error;
603 }
604
605 rc = bithenge_init_transform(expression_as_transform(self),
606 &expression_transform_ops, 0);
607 if (rc != EOK)
608 goto error;
609
610 self->expr = expr;
611 *out = expression_as_transform(self);
612 return EOK;
613
614error:
615 free(self);
616 bithenge_expression_dec_ref(expr);
617 return rc;
618}
619
620typedef struct {
621 bithenge_transform_t base;
622 bithenge_expression_t *expr;
623 bithenge_transform_t *true_xform, *false_xform;
624} if_transform_t;
625
626static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
627{
628 return &self->base;
629}
630
631static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
632{
633 return (if_transform_t *)base;
634}
635
636static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
637 bool *out)
638{
639 bithenge_node_t *cond_node;
640 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
641 if (rc != EOK)
642 return rc;
643 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
644 bithenge_node_dec_ref(cond_node);
645 return EINVAL;
646 }
647 *out = bithenge_boolean_node_value(cond_node);
648 bithenge_node_dec_ref(cond_node);
649 return EOK;
650}
651
652static int if_transform_apply(bithenge_transform_t *base,
653 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
654{
655 if_transform_t *self = transform_as_if(base);
656 bool cond;
657 int rc = if_transform_choose(self, scope, &cond);
658 if (rc != EOK)
659 return rc;
660 return bithenge_transform_apply(
661 cond ? self->true_xform : self->false_xform, scope, in, out);
662}
663
664static int if_transform_prefix_length(bithenge_transform_t *base,
665 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
666{
667 if_transform_t *self = transform_as_if(base);
668 bool cond;
669 int rc = if_transform_choose(self, scope, &cond);
670 if (rc != EOK)
671 return rc;
672 return bithenge_transform_prefix_length(
673 cond ? self->true_xform : self->false_xform, scope, in, out);
674}
675
676static void if_transform_destroy(bithenge_transform_t *base)
677{
678 if_transform_t *self = transform_as_if(base);
679 bithenge_expression_dec_ref(self->expr);
680 bithenge_transform_dec_ref(self->true_xform);
681 bithenge_transform_dec_ref(self->false_xform);
682 free(self);
683}
684
685static const bithenge_transform_ops_t if_transform_ops = {
686 .apply = if_transform_apply,
687 .prefix_length = if_transform_prefix_length,
688 .destroy = if_transform_destroy,
689};
690
691/** Create a transform that applies either of two transforms depending on a
692 * boolean expression. Takes references to @a expr, @a true_xform, and
693 * @a false_xform.
694 * @param[out] out Holds the new transform.
695 * @param expr The boolean expression to evaluate.
696 * @param true_xform The transform to apply if the expression is true.
697 * @param false_xform The transform to apply if the expression is false.
698 * @return EOK on success or an error code from errno.h. */
699int bithenge_if_transform(bithenge_transform_t **out,
700 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
701 bithenge_transform_t *false_xform)
702{
703 int rc;
704 if_transform_t *self = malloc(sizeof(*self));
705 if (!self) {
706 rc = ENOMEM;
707 goto error;
708 }
709
710 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
711 0);
712 if (rc != EOK)
713 goto error;
714
715 self->expr = expr;
716 self->true_xform = true_xform;
717 self->false_xform = false_xform;
718 *out = if_as_transform(self);
719 return EOK;
720
721error:
722 free(self);
723 bithenge_expression_dec_ref(expr);
724 bithenge_transform_dec_ref(true_xform);
725 bithenge_transform_dec_ref(false_xform);
726 return rc;
727}
728
729/** @}
730 */
Note: See TracBrowser for help on using the repository browser.