HelenOS sources
This source file includes following definitions.
- seq_as_node
- node_as_seq
- seq_node_field_offset
- seq_node_subtransform
- seq_node_complete
- seq_node_destroy
- seq_node_set_num_xforms
- seq_node_scope
- seq_node_init
- struct_as_transform
- transform_as_struct
- struct_as_seq
- seq_as_struct
- struct_as_node
- node_as_struct
- struct_node_for_each
- struct_node_get
- struct_node_destroy
- struct_node_get_transform
- struct_transform_make_node
- struct_transform_apply
- struct_transform_prefix_length
- struct_transform_prefix_apply
- free_subtransforms
- struct_transform_destroy
- bithenge_new_struct
- repeat_as_transform
- transform_as_repeat
- repeat_as_seq
- seq_as_repeat
- repeat_as_node
- node_as_repeat
- repeat_node_for_each
- repeat_node_get
- repeat_node_destroy
- repeat_node_get_transform
- repeat_transform_make_node
- repeat_transform_apply
- repeat_transform_prefix_apply
- repeat_transform_destroy
- bithenge_repeat_transform
- do_while_as_transform
- transform_as_do_while
- do_while_as_seq
- seq_as_do_while
- do_while_as_node
- node_as_do_while
- do_while_node_for_each
- do_while_node_destroy
- do_while_node_get_transform
- do_while_transform_make_node
- for_each_noop
- do_while_transform_prefix_apply
- do_while_transform_destroy
- bithenge_do_while_transform
#include <stdlib.h>
#include <bithenge/blob.h>
#include <bithenge/expression.h>
#include <bithenge/sequence.h>
#include <bithenge/tree.h>
#include "common.h"
typedef struct {
bithenge_node_t base;
const struct seq_node_ops *ops;
bithenge_blob_t *blob;
bithenge_scope_t *scope;
aoff64_t *ends;
size_t num_ends;
bool end_on_empty;
bithenge_int_t num_xforms;
} seq_node_t;
typedef struct seq_node_ops {
errno_t (*get_transform)(seq_node_t *self, bithenge_transform_t **out,
bithenge_int_t index);
} seq_node_ops_t;
static bithenge_node_t *seq_as_node(seq_node_t *node)
{
return &node->base;
}
static seq_node_t *node_as_seq(bithenge_node_t *node)
{
return (seq_node_t *)node;
}
static errno_t seq_node_field_offset(seq_node_t *self, aoff64_t *out, size_t index)
{
if (index == 0) {
*out = 0;
return EOK;
}
index--;
aoff64_t prev_offset =
self->num_ends ? self->ends[self->num_ends - 1] : 0;
for (; self->num_ends <= index; self->num_ends++) {
bithenge_transform_t *subxform;
errno_t rc = self->ops->get_transform(self, &subxform,
self->num_ends);
if (rc != EOK)
return rc;
bithenge_node_t *subblob_node;
bithenge_blob_inc_ref(self->blob);
rc = bithenge_new_offset_blob(&subblob_node, self->blob,
prev_offset);
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
return rc;
}
if (self->end_on_empty) {
bool empty;
rc = bithenge_blob_empty(
bithenge_node_as_blob(subblob_node), &empty);
if (rc == EOK && empty) {
self->num_xforms = self->num_ends;
rc = ENOENT;
}
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
bithenge_node_dec_ref(subblob_node);
return rc;
}
}
bithenge_blob_t *subblob = bithenge_node_as_blob(subblob_node);
aoff64_t field_size;
rc = bithenge_transform_prefix_length(subxform, self->scope,
subblob, &field_size);
bithenge_node_dec_ref(subblob_node);
bithenge_transform_dec_ref(subxform);
if (rc != EOK)
return rc;
if (self->num_xforms == -1) {
aoff64_t *new_ends = realloc(self->ends,
(self->num_ends + 1) * sizeof(*new_ends));
if (!new_ends)
return ENOMEM;
self->ends = new_ends;
}
prev_offset = self->ends[self->num_ends] =
prev_offset + field_size;
}
*out = self->ends[index];
return EOK;
}
static errno_t seq_node_subtransform(seq_node_t *self, bithenge_node_t **out,
size_t index)
{
aoff64_t start_pos;
errno_t rc = seq_node_field_offset(self, &start_pos, index);
if (rc != EOK)
return rc;
bithenge_transform_t *subxform;
rc = self->ops->get_transform(self, &subxform, index);
if (rc != EOK)
return rc;
if (index == self->num_ends) {
bithenge_node_t *blob_node;
bithenge_blob_inc_ref(self->blob);
rc = bithenge_new_offset_blob(&blob_node, self->blob,
start_pos);
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
return rc;
}
if (self->end_on_empty) {
bool empty;
rc = bithenge_blob_empty(
bithenge_node_as_blob(blob_node), &empty);
if (rc == EOK && empty) {
self->num_xforms = self->num_ends;
rc = ENOENT;
}
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
bithenge_node_dec_ref(blob_node);
return rc;
}
}
aoff64_t size;
rc = bithenge_transform_prefix_apply(subxform, self->scope,
bithenge_node_as_blob(blob_node), out, &size);
bithenge_node_dec_ref(blob_node);
bithenge_transform_dec_ref(subxform);
if (rc != EOK)
return rc;
if (self->num_xforms == -1) {
aoff64_t *new_ends = realloc(self->ends,
(self->num_ends + 1) * sizeof(*new_ends));
if (!new_ends)
return ENOMEM;
self->ends = new_ends;
}
self->ends[self->num_ends++] = start_pos + size;
} else {
aoff64_t end_pos;
errno_t rc = seq_node_field_offset(self, &end_pos, index + 1);
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
return rc;
}
bithenge_node_t *blob_node;
bithenge_blob_inc_ref(self->blob);
rc = bithenge_new_subblob(&blob_node, self->blob, start_pos,
end_pos - start_pos);
if (rc != EOK) {
bithenge_transform_dec_ref(subxform);
return rc;
}
rc = bithenge_transform_apply(subxform, self->scope, blob_node,
out);
bithenge_node_dec_ref(blob_node);
bithenge_transform_dec_ref(subxform);
if (rc != EOK)
return rc;
}
return EOK;
}
static errno_t seq_node_complete(seq_node_t *self, bool *out)
{
aoff64_t blob_size, end_pos;
errno_t rc = bithenge_blob_size(self->blob, &blob_size);
if (rc != EOK)
return rc;
rc = seq_node_field_offset(self, &end_pos, self->num_xforms);
if (rc != EOK)
return rc;
*out = blob_size == end_pos;
return EOK;
}
static void seq_node_destroy(seq_node_t *self)
{
bithenge_scope_dec_ref(self->scope);
bithenge_blob_dec_ref(self->blob);
free(self->ends);
}
static void seq_node_set_num_xforms(seq_node_t *self,
bithenge_int_t num_xforms)
{
self->num_xforms = num_xforms;
}
static bithenge_scope_t *seq_node_scope(seq_node_t *self)
{
return self->scope;
}
static errno_t seq_node_init(seq_node_t *self, const seq_node_ops_t *ops,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_int_t num_xforms,
bool end_on_empty)
{
self->ops = ops;
if (num_xforms != -1) {
self->ends = malloc(sizeof(*self->ends) * num_xforms);
if (!self->ends)
return ENOMEM;
} else
self->ends = NULL;
bithenge_blob_inc_ref(blob);
self->blob = blob;
self->num_xforms = num_xforms;
self->num_ends = 0;
self->end_on_empty = end_on_empty;
self->scope = scope;
if (self->scope)
bithenge_scope_inc_ref(self->scope);
return EOK;
}
typedef struct {
bithenge_transform_t base;
bithenge_named_transform_t *subtransforms;
size_t num_subtransforms;
} struct_transform_t;
static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
{
return &xform->base;
}
static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
{
return (struct_transform_t *)xform;
}
typedef struct {
seq_node_t base;
struct_transform_t *transform;
bool prefix;
} struct_node_t;
static seq_node_t *struct_as_seq(struct_node_t *node)
{
return &node->base;
}
static struct_node_t *seq_as_struct(seq_node_t *base)
{
return (struct_node_t *)base;
}
static bithenge_node_t *struct_as_node(struct_node_t *node)
{
return seq_as_node(struct_as_seq(node));
}
static struct_node_t *node_as_struct(bithenge_node_t *node)
{
return seq_as_struct(node_as_seq(node));
}
static errno_t struct_node_for_each(bithenge_node_t *base,
bithenge_for_each_func_t func, void *data)
{
errno_t rc = EOK;
struct_node_t *self = node_as_struct(base);
bithenge_named_transform_t *subxforms =
self->transform->subtransforms;
for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
bithenge_node_t *subxform_result;
rc = seq_node_subtransform(struct_as_seq(self),
&subxform_result, i);
if (rc != EOK)
return rc;
if (subxforms[i].name) {
bithenge_node_t *name_node;
rc = bithenge_new_string_node(&name_node,
subxforms[i].name, false);
if (rc == EOK) {
rc = func(name_node, subxform_result, data);
subxform_result = NULL;
}
} else {
if (bithenge_node_type(subxform_result) !=
BITHENGE_NODE_INTERNAL) {
rc = EINVAL;
} else {
rc = bithenge_node_for_each(subxform_result,
func, data);
}
}
bithenge_node_dec_ref(subxform_result);
if (rc != EOK)
return rc;
}
if (!self->prefix) {
bool complete;
rc = seq_node_complete(struct_as_seq(self), &complete);
if (rc != EOK)
return rc;
if (!complete)
return EINVAL;
}
return rc;
}
static errno_t struct_node_get(bithenge_node_t *base, bithenge_node_t *key,
bithenge_node_t **out)
{
struct_node_t *self = node_as_struct(base);
errno_t rc = ENOENT;
if (bithenge_node_type(key) != BITHENGE_NODE_STRING)
goto end;
const char *name = bithenge_string_node_value(key);
const bithenge_named_transform_t *subxforms =
self->transform->subtransforms;
for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
if (subxforms[i].name && !str_cmp(name, subxforms[i].name)) {
rc = seq_node_subtransform(struct_as_seq(self), out, i);
goto end;
}
}
for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
if (subxforms[i].name)
continue;
bithenge_node_t *subxform_result;
rc = seq_node_subtransform(struct_as_seq(self),
&subxform_result, i);
if (rc != EOK)
goto end;
if (bithenge_node_type(subxform_result) !=
BITHENGE_NODE_INTERNAL) {
bithenge_node_dec_ref(subxform_result);
rc = EINVAL;
goto end;
}
bithenge_node_inc_ref(key);
rc = bithenge_node_get(subxform_result, key, out);
bithenge_node_dec_ref(subxform_result);
if (rc != ENOENT)
goto end;
}
rc = ENOENT;
end:
bithenge_node_dec_ref(key);
return rc;
}
static void struct_node_destroy(bithenge_node_t *base)
{
struct_node_t *node = node_as_struct(base);
bithenge_scope_t *scope = seq_node_scope(struct_as_seq(node));
if (scope->refs == 1) {
scope->current_node = NULL;
seq_node_destroy(struct_as_seq(node));
} else if (scope->refs > 1) {
bithenge_node_inc_ref(base);
bithenge_scope_dec_ref(scope);
return;
} else {
struct_as_seq(node)->scope = NULL;
seq_node_destroy(struct_as_seq(node));
}
bithenge_transform_dec_ref(struct_as_transform(node->transform));
free(node);
}
static const bithenge_internal_node_ops_t struct_node_ops = {
.for_each = struct_node_for_each,
.get = struct_node_get,
.destroy = struct_node_destroy,
};
static errno_t struct_node_get_transform(seq_node_t *base,
bithenge_transform_t **out, bithenge_int_t index)
{
struct_node_t *self = seq_as_struct(base);
*out = self->transform->subtransforms[index].transform;
bithenge_transform_inc_ref(*out);
return EOK;
}
static const seq_node_ops_t struct_node_seq_ops = {
.get_transform = struct_node_get_transform,
};
static errno_t struct_transform_make_node(struct_transform_t *self,
bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
bool prefix)
{
struct_node_t *node = malloc(sizeof(*node));
if (!node)
return ENOMEM;
errno_t rc = bithenge_init_internal_node(struct_as_node(node),
&struct_node_ops);
if (rc != EOK) {
free(node);
return rc;
}
bithenge_scope_t *inner;
rc = bithenge_scope_new(&inner, scope);
if (rc != EOK) {
free(node);
return rc;
}
rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, inner,
blob, self->num_subtransforms, false);
if (rc != EOK) {
bithenge_scope_dec_ref(inner);
free(node);
return rc;
}
bithenge_transform_inc_ref(struct_as_transform(self));
node->transform = self;
node->prefix = prefix;
bithenge_scope_set_current_node(inner, struct_as_node(node));
bithenge_scope_dec_ref(inner);
*out = struct_as_node(node);
return EOK;
}
static errno_t struct_transform_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
struct_transform_t *self = transform_as_struct(base);
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
return struct_transform_make_node(self, out, scope,
bithenge_node_as_blob(in), false);
}
static errno_t struct_transform_prefix_length(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
{
struct_transform_t *self = transform_as_struct(base);
bithenge_node_t *struct_node;
errno_t rc = struct_transform_make_node(self, &struct_node, scope, blob,
true);
if (rc != EOK)
return rc;
rc = seq_node_field_offset(node_as_seq(struct_node), out,
self->num_subtransforms);
bithenge_node_dec_ref(struct_node);
return rc;
}
static errno_t struct_transform_prefix_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
struct_transform_t *self = transform_as_struct(base);
errno_t rc = struct_transform_make_node(self, out_node, scope, blob,
true);
if (rc != EOK)
return rc;
if (out_size) {
rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
self->num_subtransforms);
if (rc != EOK) {
bithenge_node_dec_ref(*out_node);
return rc;
}
}
return EOK;
}
static void free_subtransforms(bithenge_named_transform_t *subtransforms)
{
for (size_t i = 0; subtransforms[i].transform; i++) {
free((void *)subtransforms[i].name);
bithenge_transform_dec_ref(subtransforms[i].transform);
}
free(subtransforms);
}
static void struct_transform_destroy(bithenge_transform_t *base)
{
struct_transform_t *self = transform_as_struct(base);
free_subtransforms(self->subtransforms);
free(self);
}
static bithenge_transform_ops_t struct_transform_ops = {
.apply = struct_transform_apply,
.prefix_length = struct_transform_prefix_length,
.prefix_apply = struct_transform_prefix_apply,
.destroy = struct_transform_destroy,
};
errno_t bithenge_new_struct(bithenge_transform_t **out,
bithenge_named_transform_t *subtransforms)
{
errno_t rc;
struct_transform_t *self = malloc(sizeof(*self));
if (!self) {
rc = ENOMEM;
goto error;
}
rc = bithenge_init_transform(struct_as_transform(self),
&struct_transform_ops, 0);
if (rc != EOK)
goto error;
self->subtransforms = subtransforms;
self->num_subtransforms = 0;
while (subtransforms[self->num_subtransforms].transform)
self->num_subtransforms++;
*out = struct_as_transform(self);
return EOK;
error:
free_subtransforms(subtransforms);
free(self);
return rc;
}
typedef struct {
bithenge_transform_t base;
bithenge_expression_t *expr;
bithenge_transform_t *xform;
} repeat_transform_t;
static inline bithenge_transform_t *repeat_as_transform(
repeat_transform_t *self)
{
return &self->base;
}
static inline repeat_transform_t *transform_as_repeat(
bithenge_transform_t *base)
{
return (repeat_transform_t *)base;
}
typedef struct {
seq_node_t base;
bool prefix;
bithenge_int_t count;
bithenge_transform_t *xform;
} repeat_node_t;
static seq_node_t *repeat_as_seq(repeat_node_t *self)
{
return &self->base;
}
static repeat_node_t *seq_as_repeat(seq_node_t *base)
{
return (repeat_node_t *)base;
}
static bithenge_node_t *repeat_as_node(repeat_node_t *self)
{
return seq_as_node(repeat_as_seq(self));
}
static repeat_node_t *node_as_repeat(bithenge_node_t *base)
{
return seq_as_repeat(node_as_seq(base));
}
static errno_t repeat_node_for_each(bithenge_node_t *base,
bithenge_for_each_func_t func, void *data)
{
errno_t rc = EOK;
repeat_node_t *self = node_as_repeat(base);
for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
bithenge_node_t *subxform_result;
rc = seq_node_subtransform(repeat_as_seq(self),
&subxform_result, i);
if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
self->count = i;
seq_node_set_num_xforms(repeat_as_seq(self),
self->count);
rc = EOK;
break;
}
if (rc != EOK)
return rc;
bithenge_node_t *key_node;
rc = bithenge_new_integer_node(&key_node, i);
if (rc != EOK) {
bithenge_node_dec_ref(subxform_result);
return rc;
}
rc = func(key_node, subxform_result, data);
if (rc != EOK)
return rc;
}
if (!self->prefix) {
bool complete;
rc = seq_node_complete(repeat_as_seq(self), &complete);
if (rc != EOK)
return rc;
if (!complete)
return EINVAL;
}
return rc;
}
static errno_t repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
bithenge_node_t **out)
{
repeat_node_t *self = node_as_repeat(base);
if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(key);
return ENOENT;
}
bithenge_int_t index = bithenge_integer_node_value(key);
bithenge_node_dec_ref(key);
if (index < 0 || (self->count != -1 && index >= self->count))
return ENOENT;
return seq_node_subtransform(repeat_as_seq(self), out, index);
}
static void repeat_node_destroy(bithenge_node_t *base)
{
repeat_node_t *self = node_as_repeat(base);
seq_node_destroy(repeat_as_seq(self));
bithenge_transform_dec_ref(self->xform);
free(self);
}
static const bithenge_internal_node_ops_t repeat_node_ops = {
.for_each = repeat_node_for_each,
.get = repeat_node_get,
.destroy = repeat_node_destroy,
};
static errno_t repeat_node_get_transform(seq_node_t *base,
bithenge_transform_t **out, bithenge_int_t index)
{
repeat_node_t *self = seq_as_repeat(base);
*out = self->xform;
bithenge_transform_inc_ref(*out);
return EOK;
}
static const seq_node_ops_t repeat_node_seq_ops = {
.get_transform = repeat_node_get_transform,
};
static errno_t repeat_transform_make_node(repeat_transform_t *self,
bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
bool prefix)
{
bithenge_int_t count = -1;
if (self->expr != NULL) {
bithenge_node_t *count_node;
errno_t rc = bithenge_expression_evaluate(self->expr, scope,
&count_node);
if (rc != EOK)
return rc;
if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(count_node);
return EINVAL;
}
count = bithenge_integer_node_value(count_node);
bithenge_node_dec_ref(count_node);
if (count < 0)
return EINVAL;
}
repeat_node_t *node = malloc(sizeof(*node));
if (!node)
return ENOMEM;
errno_t rc = bithenge_init_internal_node(repeat_as_node(node),
&repeat_node_ops);
if (rc != EOK) {
free(node);
return rc;
}
rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
blob, count, count == -1);
if (rc != EOK) {
free(node);
return rc;
}
bithenge_transform_inc_ref(self->xform);
node->xform = self->xform;
node->count = count;
node->prefix = prefix;
*out = repeat_as_node(node);
return EOK;
}
static errno_t repeat_transform_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
repeat_transform_t *self = transform_as_repeat(base);
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
return repeat_transform_make_node(self, out, scope,
bithenge_node_as_blob(in), false);
}
static errno_t repeat_transform_prefix_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
repeat_transform_t *self = transform_as_repeat(base);
errno_t rc = repeat_transform_make_node(self, out_node, scope, blob, true);
if (rc != EOK)
return rc;
if (out_size) {
bithenge_int_t count = node_as_repeat(*out_node)->count;
if (count != -1) {
rc = seq_node_field_offset(node_as_seq(*out_node),
out_size, count);
if (rc != EOK) {
bithenge_node_dec_ref(*out_node);
return rc;
}
} else {
*out_size = 0;
for (count = 1; ; count++) {
aoff64_t size;
rc = seq_node_field_offset(
node_as_seq(*out_node), &size, count);
if (rc == EINVAL || rc == ENOENT)
break;
if (rc != EOK) {
bithenge_node_dec_ref(*out_node);
return rc;
}
*out_size = size;
}
}
}
return EOK;
}
static void repeat_transform_destroy(bithenge_transform_t *base)
{
repeat_transform_t *self = transform_as_repeat(base);
bithenge_transform_dec_ref(self->xform);
bithenge_expression_dec_ref(self->expr);
free(self);
}
static const bithenge_transform_ops_t repeat_transform_ops = {
.apply = repeat_transform_apply,
.prefix_apply = repeat_transform_prefix_apply,
.destroy = repeat_transform_destroy,
};
errno_t bithenge_repeat_transform(bithenge_transform_t **out,
bithenge_transform_t *xform, bithenge_expression_t *expr)
{
errno_t rc;
repeat_transform_t *self = malloc(sizeof(*self));
if (!self) {
rc = ENOMEM;
goto error;
}
rc = bithenge_init_transform(repeat_as_transform(self),
&repeat_transform_ops, 0);
if (rc != EOK)
goto error;
self->expr = expr;
self->xform = xform;
*out = repeat_as_transform(self);
return EOK;
error:
free(self);
bithenge_expression_dec_ref(expr);
bithenge_transform_dec_ref(xform);
return rc;
}
typedef struct {
bithenge_transform_t base;
bithenge_expression_t *expr;
bithenge_transform_t *xform;
} do_while_transform_t;
static inline bithenge_transform_t *do_while_as_transform(
do_while_transform_t *self)
{
return &self->base;
}
static inline do_while_transform_t *transform_as_do_while(
bithenge_transform_t *base)
{
return (do_while_transform_t *)base;
}
typedef struct {
seq_node_t base;
bithenge_expression_t *expr;
bithenge_transform_t *xform;
bithenge_int_t count;
} do_while_node_t;
static seq_node_t *do_while_as_seq(do_while_node_t *self)
{
return &self->base;
}
static do_while_node_t *seq_as_do_while(seq_node_t *base)
{
return (do_while_node_t *)base;
}
static bithenge_node_t *do_while_as_node(do_while_node_t *self)
{
return seq_as_node(do_while_as_seq(self));
}
static do_while_node_t *node_as_do_while(bithenge_node_t *base)
{
return seq_as_do_while(node_as_seq(base));
}
static errno_t do_while_node_for_each(bithenge_node_t *base,
bithenge_for_each_func_t func, void *data)
{
errno_t rc = EOK;
do_while_node_t *self = node_as_do_while(base);
for (bithenge_int_t i = 0; ; i++) {
bithenge_node_t *subxform_result;
rc = seq_node_subtransform(do_while_as_seq(self),
&subxform_result, i);
if (rc != EOK)
return rc;
bithenge_node_t *key_node;
rc = bithenge_new_integer_node(&key_node, i);
if (rc != EOK) {
bithenge_node_dec_ref(subxform_result);
return rc;
}
bithenge_node_inc_ref(subxform_result);
rc = func(key_node, subxform_result, data);
if (rc != EOK) {
bithenge_node_dec_ref(subxform_result);
return rc;
}
bithenge_scope_t *scope;
rc = bithenge_scope_new(&scope,
seq_node_scope(do_while_as_seq(self)));
if (rc != EOK) {
bithenge_node_dec_ref(subxform_result);
return rc;
}
bithenge_scope_set_current_node(scope, subxform_result);
bithenge_node_t *expr_result;
rc = bithenge_expression_evaluate(self->expr, scope,
&expr_result);
bithenge_scope_dec_ref(scope);
if (rc != EOK)
return rc;
if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
bithenge_node_dec_ref(expr_result);
return EINVAL;
}
bool cond = bithenge_boolean_node_value(expr_result);
bithenge_node_dec_ref(expr_result);
if (!cond) {
self->count = i + 1;
seq_node_set_num_xforms(do_while_as_seq(self),
self->count);
break;
}
}
return rc;
}
static void do_while_node_destroy(bithenge_node_t *base)
{
do_while_node_t *self = node_as_do_while(base);
seq_node_destroy(do_while_as_seq(self));
bithenge_expression_dec_ref(self->expr);
bithenge_transform_dec_ref(self->xform);
free(self);
}
static const bithenge_internal_node_ops_t do_while_node_ops = {
.for_each = do_while_node_for_each,
.destroy = do_while_node_destroy,
};
static errno_t do_while_node_get_transform(seq_node_t *base,
bithenge_transform_t **out, bithenge_int_t index)
{
do_while_node_t *self = seq_as_do_while(base);
*out = self->xform;
bithenge_transform_inc_ref(*out);
return EOK;
}
static const seq_node_ops_t do_while_node_seq_ops = {
.get_transform = do_while_node_get_transform,
};
static errno_t do_while_transform_make_node(do_while_transform_t *self,
bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob)
{
do_while_node_t *node = malloc(sizeof(*node));
if (!node)
return ENOMEM;
errno_t rc = bithenge_init_internal_node(do_while_as_node(node),
&do_while_node_ops);
if (rc != EOK) {
free(node);
return rc;
}
rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
scope, blob, -1, false);
if (rc != EOK) {
free(node);
return rc;
}
bithenge_transform_inc_ref(self->xform);
node->xform = self->xform;
bithenge_expression_inc_ref(self->expr);
node->expr = self->expr;
node->count = -1;
*out = do_while_as_node(node);
return EOK;
}
static errno_t for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
void *data)
{
bithenge_node_dec_ref(key);
bithenge_node_dec_ref(value);
return EOK;
}
static errno_t do_while_transform_prefix_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
do_while_transform_t *self = transform_as_do_while(base);
errno_t rc = do_while_transform_make_node(self, out_node, scope, blob);
if (rc != EOK)
return rc;
if (out_size) {
rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
if (rc != EOK) {
bithenge_node_dec_ref(*out_node);
return rc;
}
rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
node_as_do_while(*out_node)->count);
if (rc != EOK) {
bithenge_node_dec_ref(*out_node);
return rc;
}
}
return EOK;
}
static void do_while_transform_destroy(bithenge_transform_t *base)
{
do_while_transform_t *self = transform_as_do_while(base);
bithenge_transform_dec_ref(self->xform);
bithenge_expression_dec_ref(self->expr);
free(self);
}
static const bithenge_transform_ops_t do_while_transform_ops = {
.prefix_apply = do_while_transform_prefix_apply,
.destroy = do_while_transform_destroy,
};
errno_t bithenge_do_while_transform(bithenge_transform_t **out,
bithenge_transform_t *xform, bithenge_expression_t *expr)
{
errno_t rc;
do_while_transform_t *self = malloc(sizeof(*self));
if (!self) {
rc = ENOMEM;
goto error;
}
rc = bithenge_init_transform(do_while_as_transform(self),
&do_while_transform_ops, 0);
if (rc != EOK)
goto error;
self->expr = expr;
self->xform = xform;
*out = do_while_as_transform(self);
return EOK;
error:
free(self);
bithenge_expression_dec_ref(expr);
bithenge_transform_dec_ref(xform);
return rc;
}
HelenOS homepage, sources at GitHub