~lbnz/xr0

d5031454c39a42dc5756abbe32d94889bd425ad0 — Leibniz Founders 7 months ago acc249d
removed value, object, externals from state
11 files changed, 255 insertions(+), 314 deletions(-)

M Makefile
A include/ext.h
R src/state/object.h => include/object.h
M include/state.h
R src/state/value.h => include/value.h
M main.c
A src/ext/ext.c
R src/{state/object.c => object/object.c}
M src/state/state.c
R src/{state/value.c => value/value.c}
M src/verify/verify.c
M Makefile => Makefile +14 -5
@@ 10,8 10,11 @@ BIN_DIR = bin
BUILD_DIR = build
INCLUDE_DIR = include
SRC_DIR = src
EXT_DIR = $(SRC_DIR)/ext
VERIFY_DIR = $(SRC_DIR)/verify
STATE_DIR = $(SRC_DIR)/state
OBJECT_DIR = $(SRC_DIR)/object
VALUE_DIR = $(SRC_DIR)/value
AST_DIR = $(SRC_DIR)/ast
UTIL_DIR = $(SRC_DIR)/util
MATH_DIR = $(SRC_DIR)/math


@@ 24,6 27,7 @@ MAIN_OBJ = $(BUILD_DIR)/main.o
VERIFY_OBJ = $(BUILD_DIR)/verify.o

STATE_OBJ = $(BUILD_DIR)/state.o
EXT_OBJ = $(BUILD_DIR)/ext.o
STACK_OBJ = $(BUILD_DIR)/stack.o
HEAP_OBJ = $(BUILD_DIR)/heap.o
LOCATION_OBJ = $(BUILD_DIR)/location.o


@@ 54,7 58,8 @@ STATE_OBJECTS = $(VALUE_OBJ) \
		$(OBJECT_OBJ) \
		$(BLOCK_OBJ) \
		$(HEAP_OBJ) \
		$(STACK_OBJ)
		$(STACK_OBJ) \
		$(EXT_OBJ)

OBJECTS = $(XR0_OBJECTS) $(STATE_OBJECTS)



@@ 85,6 90,10 @@ $(STATE_OBJ): $(STATE_DIR)/state.c $(STATE_OBJECTS)
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(STATE_DIR)/state.c

$(EXT_OBJ): $(EXT_DIR)/ext.c
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(EXT_DIR)/ext.c

$(STACK_OBJ): $(STATE_DIR)/stack.c $(BLOCK_OBJ)
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(STATE_DIR)/stack.c


@@ 97,13 106,13 @@ $(BLOCK_OBJ): $(STATE_DIR)/block.c $(OBJECT_OBJ)
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(STATE_DIR)/block.c

$(OBJECT_OBJ): $(STATE_DIR)/object.c $(VALUE_OBJ)
$(OBJECT_OBJ): $(OBJECT_DIR)/object.c $(VALUE_OBJ)
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(STATE_DIR)/object.c
	@$(CC) $(CFLAGS) -o $@ -c $(OBJECT_DIR)/object.c

$(VALUE_OBJ): $(STATE_DIR)/value.c $(LOCATION_OBJ)
$(VALUE_OBJ): $(VALUE_DIR)/value.c $(LOCATION_OBJ)
	@printf 'CC\t$@\n'
	@$(CC) $(CFLAGS) -o $@ -c $(STATE_DIR)/value.c
	@$(CC) $(CFLAGS) -o $@ -c $(VALUE_DIR)/value.c

$(LOCATION_OBJ): $(STATE_DIR)/location.c $(UTIL_OBJ)
	@printf 'CC\t$@\n'

A include/ext.h => include/ext.h +34 -0
@@ 0,0 1,34 @@
#ifndef EXT_H
#define EXT_H

struct externals;

struct externals *
externals_create();

void
externals_destroy(struct externals *);

char *
externals_types_str(struct externals *, char *indent);

struct ast_function;
struct ast_variable;
struct ast_type;

void
externals_declarefunc(struct externals *, char *id, struct ast_function *);

void
externals_declarevar(struct externals *, char *id, struct ast_variable *);

void
externals_declaretype(struct externals *, char *id, struct ast_type *type);

struct ast_function *
externals_getfunc(struct externals *, char *id);

struct ast_type *
externals_gettype(struct externals *, char *id);

#endif

R src/state/object.h => include/object.h +12 -0
@@ 26,9 26,13 @@ object_lower(struct object *);
struct ast_expr *
object_upper(struct object *);

struct state;

bool
object_isdeallocand(struct object *, struct state *);

struct location;

bool
object_references(struct object *, struct location *, struct state *);



@@ 54,6 58,14 @@ object_upto(struct object *, struct ast_expr *excl_upper, struct state *);
struct object *
object_from(struct object *, struct ast_expr *incl_lower, struct state *);

struct object *
object_getmember(struct object *obj, struct ast_type *t, char *member,
		struct state *s);

struct ast_type *
object_getmembertype(struct object *obj, struct ast_type *t, char *member,
		struct state *s);

struct error *
object_dealloc(struct object *, struct state *);


M include/state.h => include/state.h +39 -105
@@ 3,40 3,23 @@

#include <stdbool.h>

struct externals;

struct externals *
externals_create();

void
externals_destroy(struct externals *);
#define KEYWORD_RESULT "result"

struct ast_function;
struct ast_variable;
/* ast */
struct ast_type;
struct ast_variable;
struct ast_expr;

void
externals_declarefunc(struct externals *, char *id, struct ast_function *);

void
externals_declarevar(struct externals *, char *id, struct ast_variable *);

void
externals_declaretype(struct externals *, char *id, struct ast_type *type);

struct ast_function *
externals_getfunc(struct externals *, char *id);

struct ast_type *
externals_gettype(struct externals *, char *id);

/* externals */
struct externals;

#define KEYWORD_RESULT "result"
/* object */
struct object;

/* util.h */
/* value */
struct value;

struct state;
struct ast_type;

struct state *
state_create(struct externals *, struct ast_type *result_type);


@@ 50,8 33,8 @@ state_destroy(struct state *state);
char *
state_str(struct state *);

struct ast_function *
state_getfunc(struct state *, char *f);
struct externals *
state_getext(struct state *);

void
state_pushframe(struct state *, struct ast_type *ret_type);


@@ 59,52 42,24 @@ state_pushframe(struct state *, struct ast_type *ret_type);
void
state_popframe(struct state *);

struct ast_variable;

void
state_declare(struct state *, struct ast_variable *var, bool isparam);

void
state_stack_undeclare(struct state *s);

struct location;

struct object *
state_get(struct state *state, struct location *loc, bool constructive);

struct block *
state_getblock(struct state *state, struct location *loc);

struct variable;
struct object;

struct object *
state_getresult(struct state *);

struct ast_expr;
state_undeclarevars(struct state *s);

struct ast_type *
state_gettype(struct state *, char *id);

struct object *
state_getobject(struct state *, char *id);
state_getresult(struct state *);

struct object *
state_getobjectmember(struct state *, struct object *, struct ast_type *,
		char *member);

struct ast_type *
state_getobjectmembertype(struct state *state, struct object *obj,
		struct ast_type *t, char *member);

struct value;
state_getobject(struct state *, char *id);

struct object *
state_deref(struct state *, struct value *ptr, struct ast_expr *index);

struct error *
state_assign(struct state *, struct object *, struct value *);

struct value *
state_alloc(struct state *);



@@ 120,9 75,6 @@ state_range_dealloc(struct state *, struct object *,
		struct ast_expr *lw, struct ast_expr *up);

bool
state_isdeallocand(struct state *s, struct location *loc);

bool
state_addresses_deallocand(struct state *, struct object *);

bool


@@ 130,66 82,48 @@ state_range_aredeallocands(struct state *, struct object *,
		struct ast_expr *lw, struct ast_expr *up);

bool
state_abstractly_equivalent(struct state *s1, struct state *s2, bool paramonly);
state_hasgarbage(struct state *);

bool
state_heap_referenced(struct state *);

void
state_object_destroy(struct object *);

void
state_value_destroy(struct value *);

struct value *
state_value_copy(struct value *);

struct value *
object_as_value(struct object *obj);

struct value *
state_getvconst(struct state *state, char *id);

struct value *
value_int_create(int val);
state_equal(struct state *s1, struct state *s2);

struct value *
value_int_range_create(int lw, int excl_up);

struct value *
value_int_sync_create(struct ast_expr *);
/* INTERNALLY USED */

struct ast_expr *
value_as_sync(struct value *v);
struct location;
struct object;

struct object *
value_struct_member(struct value *, char *member);

struct value *
value_literal_create(char *);

struct ast_expr *
value_to_expr(struct value *);
state_get(struct state *state, struct location *loc, bool constructive);

char *
value_str(struct value *);
struct block *
state_getblock(struct state *state, struct location *loc);

enum ast_binary_operator;
bool
state_isdeallocand(struct state *s, struct location *loc);

bool
value_compare(struct value *v1, enum ast_binary_operator, struct value *v2);
state_stack_references(struct state *s, struct location *loc);

struct value *
state_vconst(struct state *state);


bool
state_stack_references(struct state *s, struct location *loc);

bool
state_eval(struct state *, struct ast_expr *);


/* VALUE */

struct location *
location_copy(struct location *);

void
location_destroy(struct location *);

char *
location_str(struct location *);

bool
state_equal(struct state *s1, struct state *s2);
location_references(struct location *l1, struct location *l2, struct state *);

#endif

R src/state/value.h => include/value.h +0 -0
M main.c => main.c +1 -0
@@ 8,6 8,7 @@
#include "build/gram.tab.h"
#include "ast.h"
#include "lex.h"
#include "ext.h"
#include "state.h"
#include "util.h"
#include "verify.h"

A src/ext/ext.c => src/ext/ext.c +72 -0
@@ 0,0 1,72 @@
#include <stdlib.h>
#include "ast.h"
#include "util.h"

struct externals {
	struct map *func, *type, *var;
};

struct externals *
externals_create()
{
	struct externals *ext = malloc(sizeof(struct externals));
	ext->func = map_create();
	ext->var = map_create();
	ext->type = map_create();
	return ext;
}

void
externals_destroy(struct externals *ext)
{
	map_destroy(ext->func);
	map_destroy(ext->var);
	map_destroy(ext->type);
	free(ext);
}

char *
externals_types_str(struct externals *ext, char *indent)
{
	struct strbuilder *b = strbuilder_create();

	struct map *m = ext->type;
	for (int i = 0; i < m->n; i++) {
		char *type = ast_type_str((struct ast_type *) m->entry[i].value);
		strbuilder_printf(b, "%s%s\n", indent, type);
		free(type);
	}

	return strbuilder_build(b);
}

void
externals_declarefunc(struct externals *ext, char *id, struct ast_function *f)
{
	map_set(ext->func, dynamic_str(id), f);
}

void
externals_declarevar(struct externals *ext, char *id, struct ast_variable *v)
{
	map_set(ext->var, dynamic_str(id), v);
}

void
externals_declaretype(struct externals *ext, char *id, struct ast_type *t)
{
	map_set(ext->type, dynamic_str(id), t);
}

struct ast_function *
externals_getfunc(struct externals *ext, char *id)
{
	return map_get(ext->func, id);
}

struct ast_type *
externals_gettype(struct externals *ext, char *id)
{
	return map_get(ext->type, id);
}


R src/state/object.c => src/object/object.c +48 -2
@@ 2,10 2,9 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "ext.h"
#include "ast.h"
#include "heap.h"
#include "state.h"
#include "location.h"
#include "object.h"
#include "util.h"
#include "value.h"


@@ 399,6 398,53 @@ object_dealloc(struct object *obj, struct state *s)
	}
}

static struct value *
getorcreatestruct(struct object *, struct ast_type *, struct state *);

struct object *
object_getmember(struct object *obj, struct ast_type *t, char *member,
		struct state *s)
{
	return value_struct_member(getorcreatestruct(obj, t, s), member);
}

static struct ast_type *
usecomplete(struct ast_type *, struct state *);

static struct value *
getorcreatestruct(struct object *obj, struct ast_type *t, struct state *s)
{
	struct value *v = object_as_value(obj);
	if (v) {
		return v;
	}
	struct ast_type *complete = usecomplete(t, s);
	assert(complete);
	v = value_struct_create(complete);
	object_assign(obj, v);
	return v;
}

static struct ast_type *
usecomplete(struct ast_type *t, struct state *s)
{
	if (ast_type_struct_members(t)) {
		return t;
	}
	char *tag = ast_type_struct_tag(t);
	assert(tag);
	return externals_gettype(state_getext(s), tag);
}

struct ast_type *
object_getmembertype(struct object *obj, struct ast_type *t, char *member,
		struct state *s)
{
	return value_struct_membertype(
		getorcreatestruct(obj, t, s), member
	);
}


struct range {
	struct ast_expr *size;

M src/state/state.c => src/state/state.c +8 -144
@@ 3,6 3,7 @@
#include <assert.h>
#include <string.h>

#include "ext.h"
#include "state.h"
#include "stack.h"
#include "heap.h"


@@ 13,76 14,6 @@
#include "ast.h"
#include "util.h"

struct externals {
	struct map *func, *type, *var;
};

struct externals *
externals_create()
{
	struct externals *ext = malloc(sizeof(struct externals));
	ext->func = map_create();
	ext->var = map_create();
	ext->type = map_create();
	return ext;
}

void
externals_destroy(struct externals *ext)
{
	map_destroy(ext->func);
	map_destroy(ext->var);
	map_destroy(ext->type);
	free(ext);
}

static char *
externals_types_str(struct externals *ext, char *indent)
{
	struct strbuilder *b = strbuilder_create();

	struct map *m = ext->type;
	for (int i = 0; i < m->n; i++) {
		char *type = ast_type_str((struct ast_type *) m->entry[i].value);
		strbuilder_printf(b, "%s%s\n", indent, type);
		free(type);
	}

	return strbuilder_build(b);
}

void
externals_declarefunc(struct externals *ext, char *id, struct ast_function *f)
{
	map_set(ext->func, dynamic_str(id), f);
}

void
externals_declarevar(struct externals *ext, char *id, struct ast_variable *v)
{
	map_set(ext->var, dynamic_str(id), v);
}

void
externals_declaretype(struct externals *ext, char *id, struct ast_type *t)
{
	map_set(ext->type, dynamic_str(id), t);
}

struct ast_function *
externals_getfunc(struct externals *ext, char *id)
{
	return map_get(ext->func, id);
}

struct ast_type *
externals_gettype(struct externals *ext, char *id)
{
	return map_get(ext->type, id);
}



struct state {
	struct externals *ext;
	struct vconst *vconst;


@@ 150,6 81,13 @@ state_str(struct state *state)
	return strbuilder_build(b);
}

struct externals *
state_getext(struct state *s)
{
	return s->ext;
}


struct ast_function *
state_getfunc(struct state *state, char *f)
{


@@ 256,54 194,6 @@ state_getobject(struct state *state, char *id)
	return state_get(state, variable_location(v), true);
}

struct value *
getorcreatestruct(struct object *, struct ast_type *, struct state *);

struct object *
state_getobjectmember(struct state *state, struct object *obj,
		struct ast_type *t, char *member)
{
	return value_struct_member(
		getorcreatestruct(obj, t, state), member
	);
}

struct ast_type *
usecomplete(struct ast_type *, struct state *);

struct value *
getorcreatestruct(struct object *obj, struct ast_type *t, struct state *state)
{
	struct value *v = object_as_value(obj);
	if (v) {
		return v;
	}
	struct ast_type *complete = usecomplete(t, state);
	assert(complete);
	v = value_struct_create(complete);
	object_assign(obj, v);
	return v;
}

struct ast_type *
usecomplete(struct ast_type *t, struct state *state)
{
	if (ast_type_struct_members(t)) {
		return t;
	}
	char *tag = ast_type_struct_tag(t);
	assert(tag);
	return externals_gettype(state->ext, tag);
}

struct ast_type *
state_getobjectmembertype(struct state *state, struct object *obj,
		struct ast_type *t, char *member)
{
	return value_struct_membertype(
		getorcreatestruct(obj, t, state), member
	);
}

struct object *
state_deref(struct state *state, struct value *ptr_val, struct ast_expr *index)


@@ 319,13 209,6 @@ state_deref(struct state *state, struct value *ptr_val, struct ast_expr *index)
}

struct error *
state_assign(struct state *state, struct object *obj, struct value *val)
{
	object_assign(obj, val);
	return NULL;
}

struct error *
state_range_alloc(struct state *state, struct object *obj,
		struct ast_expr *lw, struct ast_expr *up)
{


@@ 434,25 317,6 @@ state_location_destroy(struct location *loc)
	location_destroy(loc);
}

void
state_value_destroy(struct value *val)
{
	assert(val);
	value_destroy(val);
}

struct value *
state_value_copy(struct value *v)
{
	return value_copy(v);
}

void
state_object_destroy(struct object *obj)
{
	/* XXX */
}

bool
state_stack_references(struct state *s, struct location *loc)
{

R src/state/value.c => src/value/value.c +0 -2
@@ 3,10 3,8 @@
#include <assert.h>
#include <string.h>
#include "ast.h"
#include "location.h"
#include "state.h"
#include "object.h"
#include "stack.h"
#include "util.h"
#include "value.h"


M src/verify/verify.c => src/verify/verify.c +27 -56
@@ 2,9 2,12 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "ext.h"
#include "ast.h"
#include "object.h"
#include "state.h"
#include "util.h"
#include "value.h"
#include "verify.h"

typedef struct func_arr *Funcarr;


@@ 334,7 337,7 @@ path_verify(struct ast_function *f, struct state *state, struct externals *ext)
			return error_prepend(err, "cannot exec statement: ");
		}
	}
	state_stack_undeclare(state);
	state_undeclarevars(state);
	/* TODO: verify that `result' is of same type as f->result */
	if ((err = abstract_audit(f, state, ext))) {
		return error_prepend(err, "qed error: ");


@@ 357,10 360,7 @@ parameterise_state(struct state *s, struct ast_function *f)
		if (ast_type_base(ast_variable_type(p)) == TYPE_INT) {
			struct object *obj = state_getobject(s, ast_variable_name(p));
			assert(obj);
			struct error *err = state_assign(s, obj, state_vconst(s));
			if (err) {
				return err;
			}
			object_assign(obj, state_vconst(s));
		}
	}



@@ 486,7 486,7 @@ result_destroy(struct result res)
{
	assert(!res.err);
	if (res.val) {
		state_value_destroy(res.val);
		value_destroy(res.val);
	}
}



@@ 571,7 571,6 @@ expr_assertion_decide(struct ast_expr *expr, struct state *state)
{
	struct object *obj = hack_object_from_assertion(expr, state);
	bool isdeallocand = state_addresses_deallocand(state, obj);
	state_object_destroy(obj);
	return isdeallocand;
}



@@ 694,8 693,6 @@ expr_iter_assertion_verify(struct ast_expr *expr, struct ast_expr *lw,
		state, obj, lw, up	
	);

	state_object_destroy(obj);

	return deallocands;
}



@@ 821,17 818,17 @@ expr_structmember_lvalue(struct ast_expr *expr, struct state *state)
	struct lvalue *root = expr_lvalue(ast_expr_member_root(expr), state);
	struct object *root_obj = lvalue_object(root);
	assert(root_obj);
	struct object *obj = state_getobjectmember(
		state,
	struct object *obj = object_getmember(
		root_obj,
		lvalue_type(root),
		ast_expr_member_field(expr)
		ast_expr_member_field(expr),
		state
	);
	struct ast_type *t = state_getobjectmembertype(
		state,
	struct ast_type *t = object_getmembertype(
		root_obj,
		lvalue_type(root),
		ast_expr_member_field(expr)
		ast_expr_member_field(expr),
		state
	);
	return lvalue_create(t, obj);
}


@@ 855,7 852,7 @@ void
lvalue_destroy(struct lvalue *l)
{
	ast_type_destroy(l->t);
	state_object_destroy(l->obj);
	object_destroy(l->obj);
	free(l);
}



@@ 973,7 970,7 @@ expr_identifier_eval(struct ast_expr *expr, struct state *state)
	if (!val) {
		return result_error_create(error_create("no value"));
	}
	return result_value_create(state_value_copy(val));
	return result_value_create(value_copy(val));
}

static struct result


@@ 996,7 993,7 @@ expr_unary_eval(struct ast_expr *expr, struct state *state)
	struct value *v = object_as_value(obj);
	assert(v);

	return result_value_create(state_value_copy(v));
	return result_value_create(value_copy(v));
}

static struct result


@@ 1006,7 1003,7 @@ expr_structmember_eval(struct ast_expr *expr, struct state *s)
	if (result_iserror(res)) {
		return res;
	}
	struct value *v = state_value_copy(object_as_value(
	struct value *v = value_copy(object_as_value(
		value_struct_member(
			result_as_value(res),
			ast_expr_member_field(expr)


@@ 1099,7 1096,7 @@ expr_call_eval(struct ast_expr *expr, struct state *state)
		return res;
	}
	if (result_hasvalue(res)) { /* preserve value through pop */
		res = result_value_create(state_value_copy(result_as_value(res)));
		res = result_value_create(value_copy(result_as_value(res)));
	}
	state_popframe(state);
	return res;


@@ 1112,7 1109,7 @@ expr_as_func(struct ast_expr *expr, struct state *state)
{
	struct ast_expr *root = ast_expr_call_root(expr);
	/* TODO: allow function-valued expressions */
	return state_getfunc(state, ast_expr_as_identifier(root));
	return externals_getfunc(state_getext(state), ast_expr_as_identifier(root));
}

/* call_eval_inframe */


@@ 1164,15 1161,7 @@ prepare_parameters(struct ast_function *f, struct result_arr *args,
		struct object *obj = lvalue_object(expr_lvalue(name, state));
		ast_expr_destroy(name);

		struct error *err = state_assign(
			state, obj, state_value_copy(result_as_value(res))
		);

		state_object_destroy(obj);

		if (err) {
			return err;
		}
		object_assign(obj, value_copy(result_as_value(res)));
	}
	return NULL;
}


@@ 1187,13 1176,7 @@ expr_assign_eval(struct ast_expr *expr, struct state *state)
	if (result_hasvalue(res)) {
		struct object *obj = lvalue_object(expr_lvalue(lval, state));
		assert(obj);
		struct error *err = state_assign(
			state, obj, state_value_copy(result_as_value(res))
		);
		state_object_destroy(obj);
		if (err) {
			return result_error_create(err);
		}
		object_assign(obj, value_copy(result_as_value(res)));
	}
	return res;
}


@@ 1460,7 1443,7 @@ expr_assertion_iter_decide(struct ast_expr *expr, struct ast_stmt *iter,

	bool deallocands = state_range_aredeallocands(state, obj, lw, up);

	state_object_destroy(obj);
	object_destroy(obj);

	return deallocands;
}


@@ 1494,14 1477,9 @@ stmt_jump_exec(struct ast_stmt *stmt, struct state *state)
	if (result_hasvalue(res)) {
		struct object *obj = state_getresult(state); 
		assert(obj);
		struct error *err = state_assign(
			state, obj, state_value_copy(result_as_value(res))
		);
		object_assign(obj, value_copy(result_as_value(res)));
		result_destroy(res);
		if (err) {
			return err;
		}
		state_stack_undeclare(state);
		state_undeclarevars(state);
	}
	return NULL;
}


@@ 1518,7 1496,7 @@ abstract_audit(struct ast_function *f, struct state *actual_state,
{
	struct error *err = NULL;

	if (!state_heap_referenced(actual_state)) {
	if (!state_hasgarbage(actual_state)) {
		return error_create("garbage on heap");
	}
	/*printf("actual: %s\n", state_str(actual_state));*/


@@ 1568,7 1546,7 @@ hack_flatten_abstract_for_iter_verification(struct ast_function *f,
		return ast_block_copy(abs);
	}
	/* asserts that we have `allocated' condition */
	state_object_destroy(
	object_destroy(
		hack_object_from_assertion(
			ast_stmt_sel_cond(stmt), state
		)


@@ 1669,13 1647,7 @@ mem_absexec(struct ast_expr *mem, struct state *state)
			expr_lvalue(ast_expr_memory_root(mem), state)
		);
		assert(obj);
		struct error *err = state_assign(
			state, obj, state_value_copy(result_as_value(res))
		);
		state_object_destroy(obj);
		if (err) {
			return result_error_create(err);
		}
		object_assign(obj, value_copy(result_as_value(res)));
	}
	return res;
}


@@ 1715,7 1687,7 @@ mem_process(struct ast_expr *mem, struct state *state)
		fprintf(stderr, "cannot free: %s\n", err->msg);
		assert(false);
	}
	state_value_destroy(val);
	value_destroy(val);
	return result_value_create(NULL);
}



@@ 1775,7 1747,6 @@ iter_absexec(struct ast_stmt *stmt, struct state *state)
	
	ast_expr_destroy(res_up);
	ast_expr_destroy(res_lw);
	state_object_destroy(obj);

	if (err) {
		return result_error_create(err);