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

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

Bithenge: add expressions that use the current node being created

  • Property mode set to 100644
File size: 11.1 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
65static int current_node_evaluate(bithenge_expression_t *self,
66 bithenge_scope_t *scope, bithenge_node_t **out)
67{
68 *out = bithenge_scope_get_current_node(scope);
69 if (!*out)
70 return EINVAL;
71 return EOK;
72}
73
74static const bithenge_expression_ops_t current_node_ops = {
75 .evaluate = current_node_evaluate,
76 .destroy = expression_indestructible,
77};
78
79static bithenge_expression_t current_node_expression = {
80 &current_node_ops, 1
81};
82
83/** Create an expression that gets the current node being created.
84 * @param[out] out Holds the new expression.
85 * @return EOK on success or an error code from errno.h. */
86int bithenge_current_node_expression(bithenge_expression_t **out)
87{
88 bithenge_expression_inc_ref(&current_node_expression);
89 *out = &current_node_expression;
90 return EOK;
91}
92
93typedef struct {
94 bithenge_expression_t base;
95 int index;
96} param_expression_t;
97
98static inline param_expression_t *expression_as_param(
99 bithenge_expression_t *base)
100{
101 return (param_expression_t *)base;
102}
103
104static inline bithenge_expression_t *param_as_expression(
105 param_expression_t *self)
106{
107 return &self->base;
108}
109
110static int param_expression_evaluate(bithenge_expression_t *base,
111 bithenge_scope_t *scope, bithenge_node_t **out)
112{
113 param_expression_t *self = expression_as_param(base);
114 return bithenge_scope_get_param(scope, self->index, out);
115}
116
117static void param_expression_destroy(bithenge_expression_t *base)
118{
119 param_expression_t *self = expression_as_param(base);
120 free(self);
121}
122
123static const bithenge_expression_ops_t param_expression_ops = {
124 .evaluate = param_expression_evaluate,
125 .destroy = param_expression_destroy,
126};
127
128/** Create an expression that returns a parameter.
129 * @param[out] out Holds the created expression.
130 * @param index The index of the parameter to get.
131 * @return EOK on success or an error code from errno.h. */
132int bithenge_param_expression(bithenge_expression_t **out, int index)
133{
134 int rc;
135 param_expression_t *self = malloc(sizeof(*self));
136 if (!self)
137 return ENOMEM;
138
139 rc = bithenge_init_expression(param_as_expression(self),
140 &param_expression_ops);
141 if (rc != EOK) {
142 free(self);
143 return rc;
144 }
145
146 self->index = index;
147 *out = param_as_expression(self);
148 return EOK;
149}
150
151typedef struct {
152 bithenge_expression_t base;
153 bithenge_node_t *node;
154} const_expression_t;
155
156static inline const_expression_t *expression_as_const(
157 bithenge_expression_t *base)
158{
159 return (const_expression_t *)base;
160}
161
162static inline bithenge_expression_t *const_as_expression(
163 const_expression_t *self)
164{
165 return &self->base;
166}
167
168static int const_expression_evaluate(bithenge_expression_t *base,
169 bithenge_scope_t *scope, bithenge_node_t **out)
170{
171 const_expression_t *self = expression_as_const(base);
172 bithenge_node_inc_ref(self->node);
173 *out = self->node;
174 return EOK;
175}
176
177static void const_expression_destroy(bithenge_expression_t *base)
178{
179 const_expression_t *self = expression_as_const(base);
180 bithenge_node_dec_ref(self->node);
181 free(self);
182}
183
184static const bithenge_expression_ops_t const_expression_ops = {
185 .evaluate = const_expression_evaluate,
186 .destroy = const_expression_destroy,
187};
188
189/** Create an expression that returns a constant. Takes a reference to @a node.
190 * @param[out] out Holds the created expression.
191 * @param node The constant.
192 * @return EOK on success or an error code from errno.h. */
193int bithenge_const_expression(bithenge_expression_t **out,
194 bithenge_node_t *node)
195{
196 int rc;
197 const_expression_t *self = malloc(sizeof(*self));
198 if (!self)
199 return ENOMEM;
200
201 rc = bithenge_init_expression(const_as_expression(self),
202 &const_expression_ops);
203 if (rc != EOK) {
204 free(self);
205 return rc;
206 }
207
208 self->node = node;
209 *out = const_as_expression(self);
210 return EOK;
211}
212
213typedef struct {
214 bithenge_expression_t base;
215 bithenge_expression_t *expr;
216 bithenge_node_t *key;
217} member_expression_t;
218
219static member_expression_t *expression_as_member(bithenge_expression_t *base)
220{
221 return (member_expression_t *)base;
222}
223
224static bithenge_expression_t *member_as_expression(member_expression_t *expr)
225{
226 return &expr->base;
227}
228
229static int member_expression_evaluate(bithenge_expression_t *base,
230 bithenge_scope_t *scope, bithenge_node_t **out)
231{
232 member_expression_t *self = expression_as_member(base);
233 bithenge_node_t *node;
234 int rc = bithenge_expression_evaluate(self->expr, scope, &node);
235 if (rc != EOK)
236 return rc;
237 bithenge_node_inc_ref(self->key);
238 rc = bithenge_node_get(node, self->key, out);
239 bithenge_node_dec_ref(node);
240 return rc;
241}
242
243static void member_expression_destroy(bithenge_expression_t *base)
244{
245 member_expression_t *self = expression_as_member(base);
246 bithenge_expression_dec_ref(self->expr);
247 bithenge_node_dec_ref(self->key);
248 free(self);
249}
250
251static const bithenge_expression_ops_t member_expression_ops = {
252 .evaluate = member_expression_evaluate,
253 .destroy = member_expression_destroy,
254};
255
256/** Create an expression that gets a member from a node. Takes references to
257 * @a expr and @a key.
258 * @param[out] out Holds the new expression.
259 * @param expr Calculates the node to get the member of.
260 * @param key The member to get.
261 * @return EOK on success or an error code from errno.h. */
262int bithenge_member_expression(bithenge_expression_t **out,
263 bithenge_expression_t *expr, bithenge_node_t *key)
264{
265 int rc;
266 member_expression_t *self = malloc(sizeof(*self));
267 if (!self) {
268 rc = ENOMEM;
269 goto error;
270 }
271
272 rc = bithenge_init_expression(member_as_expression(self),
273 &member_expression_ops);
274 if (rc != EOK)
275 goto error;
276
277 self->expr = expr;
278 self->key = key;
279 *out = member_as_expression(self);
280 return EOK;
281
282error:
283 bithenge_expression_dec_ref(expr);
284 bithenge_node_dec_ref(key);
285 free(self);
286 return rc;
287}
288
289typedef struct {
290 bithenge_transform_t base;
291 bithenge_transform_t *transform;
292 bithenge_expression_t **params;
293} param_wrapper_t;
294
295static inline bithenge_transform_t *param_wrapper_as_transform(
296 param_wrapper_t *self)
297{
298 return &self->base;
299}
300
301static inline param_wrapper_t *transform_as_param_wrapper(
302 bithenge_transform_t *base)
303{
304 return (param_wrapper_t *)base;
305}
306
307static int param_wrapper_fill_scope(param_wrapper_t *self, bithenge_scope_t
308 *inner, bithenge_scope_t *outer)
309{
310 int rc;
311 int num_params = bithenge_transform_num_params(self->transform);
312 rc = bithenge_scope_alloc_params(inner, num_params);
313 if (rc != EOK)
314 return rc;
315 for (int i = 0; i < num_params; i++) {
316 bithenge_node_t *node;
317 rc = bithenge_expression_evaluate(self->params[i], outer,
318 &node);
319 if (rc != EOK)
320 return rc;
321 rc = bithenge_scope_set_param(inner, i, node);
322 if (rc != EOK)
323 return rc;
324 }
325 return EOK;
326}
327
328static int param_wrapper_apply(bithenge_transform_t *base,
329 bithenge_scope_t *outer, bithenge_node_t *in, bithenge_node_t **out)
330{
331 param_wrapper_t *self = transform_as_param_wrapper(base);
332 bithenge_scope_t inner;
333 bithenge_scope_init(&inner);
334 int rc = param_wrapper_fill_scope(self, &inner, outer);
335 if (rc != EOK)
336 goto error;
337
338 rc = bithenge_transform_apply(self->transform, &inner, in, out);
339 in = NULL;
340
341error:
342 bithenge_scope_destroy(&inner);
343 return rc;
344}
345
346static int param_wrapper_prefix_length(bithenge_transform_t *base,
347 bithenge_scope_t *outer, bithenge_blob_t *in, aoff64_t *out)
348{
349 param_wrapper_t *self = transform_as_param_wrapper(base);
350 bithenge_scope_t inner;
351 bithenge_scope_init(&inner);
352 int rc = param_wrapper_fill_scope(self, &inner, outer);
353 if (rc != EOK)
354 goto error;
355
356 rc = bithenge_transform_prefix_length(self->transform, &inner, in,
357 out);
358 in = NULL;
359
360error:
361 bithenge_scope_destroy(&inner);
362 return rc;
363}
364
365static void param_wrapper_destroy(bithenge_transform_t *base)
366{
367 param_wrapper_t *self = transform_as_param_wrapper(base);
368 int num_params = bithenge_transform_num_params(self->transform);
369 bithenge_transform_dec_ref(self->transform);
370 for (int i = 0; i < num_params; i++)
371 bithenge_expression_dec_ref(self->params[i]);
372 free(self->params);
373 free(self);
374}
375
376static const bithenge_transform_ops_t param_wrapper_ops = {
377 .apply = param_wrapper_apply,
378 .prefix_length = param_wrapper_prefix_length,
379 .destroy = param_wrapper_destroy,
380};
381
382/** Create a transform that calculates parameters for another transform. Takes
383 * ownership of @a transform, @a params, and each element of @a params. The
384 * number of parameters must be correct.
385 * @param[out] out Holds the new transform.
386 * @param transform The transform for which parameters are calculated.
387 * @param params The expressions used to calculate the parameters.
388 * @return EOK on success or an error code from errno.h. */
389int bithenge_param_wrapper(bithenge_transform_t **out,
390 bithenge_transform_t *transform, bithenge_expression_t **params)
391{
392 int rc;
393 int num_params = bithenge_transform_num_params(transform);
394 param_wrapper_t *self = malloc(sizeof(*self));
395 if (!self) {
396 rc = ENOMEM;
397 goto error;
398 }
399
400 rc = bithenge_init_transform(param_wrapper_as_transform(self),
401 &param_wrapper_ops, 0);
402 if (rc != EOK)
403 goto error;
404
405 self->transform = transform;
406 self->params = params;
407 *out = param_wrapper_as_transform(self);
408 return EOK;
409
410error:
411 free(self);
412 for (int i = 0; i < num_params; i++)
413 bithenge_expression_dec_ref(params[i]);
414 free(params);
415 bithenge_transform_dec_ref(transform);
416 return rc;
417}
418
419/** @}
420 */
Note: See TracBrowser for help on using the repository browser.