Improve memory efficiency via plain ints for length
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
#ifndef _UCLISP_H_
|
#ifndef _UCLISP_H_
|
||||||
#define _UCLISP_H_
|
#define _UCLISP_H_
|
||||||
|
|
||||||
struct ucl_scope;
|
|
||||||
struct ucl_object;
|
struct ucl_object;
|
||||||
struct ucl;
|
struct ucl;
|
||||||
|
|
||||||
@@ -11,6 +10,9 @@ void ucl_delete(struct ucl* state);
|
|||||||
struct ucl_object *ucl_tokenize(struct ucl* state, const char *source);
|
struct ucl_object *ucl_tokenize(struct ucl* state, const char *source);
|
||||||
struct ucl_object *ucl_parse(struct ucl* state, const char *sexp);
|
struct ucl_object *ucl_parse(struct ucl* state, const char *sexp);
|
||||||
struct ucl_object *ucl_evaluate(struct ucl* state, struct ucl_object *sexp);
|
struct ucl_object *ucl_evaluate(struct ucl* state, struct ucl_object *sexp);
|
||||||
|
struct ucl_object *ucl_evaluate_progn(struct ucl* state, struct ucl_object *sexps);
|
||||||
|
void ucl_print_obj(struct ucl_object *obj);
|
||||||
|
|
||||||
|
|
||||||
void ucl_gc(struct ucl* ucl);
|
void ucl_gc(struct ucl* ucl);
|
||||||
|
|
||||||
|
|||||||
21
src/arena.c
21
src/arena.c
@@ -4,12 +4,8 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct ucl_arena {
|
#include "arena.h"
|
||||||
size_t object_size;
|
#include "types.h"
|
||||||
size_t capacity;
|
|
||||||
void *objects;
|
|
||||||
int *used_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DIV_ROUND_UP(numerator, denominator) \
|
#define DIV_ROUND_UP(numerator, denominator) \
|
||||||
(((numerator) + (denominator) - 1) / (denominator))
|
(((numerator) + (denominator) - 1) / (denominator))
|
||||||
@@ -24,6 +20,8 @@ struct ucl_arena *ucl_arena_create(size_t object_size, size_t capacity) {
|
|||||||
arena->capacity = capacity;
|
arena->capacity = capacity;
|
||||||
arena->objects = malloc(capacity * object_size);
|
arena->objects = malloc(capacity * object_size);
|
||||||
arena->used_map = malloc(used_map_size);
|
arena->used_map = malloc(used_map_size);
|
||||||
|
arena->stats.used = 0;
|
||||||
|
arena->stats.freed = 0;
|
||||||
|
|
||||||
memset(arena->used_map, 0, used_map_size);
|
memset(arena->used_map, 0, used_map_size);
|
||||||
|
|
||||||
@@ -49,7 +47,6 @@ void ucl_arena_map(struct ucl_arena *arena, void (*map_function)(struct ucl_aren
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_arena_gets = 0;
|
|
||||||
|
|
||||||
void *ucl_arena_get(struct ucl_arena *arena) {
|
void *ucl_arena_get(struct ucl_arena *arena) {
|
||||||
int used_map_ints = DIV_ROUND_UP(arena->capacity, INT_BITS);
|
int used_map_ints = DIV_ROUND_UP(arena->capacity, INT_BITS);
|
||||||
@@ -67,7 +64,7 @@ void *ucl_arena_get(struct ucl_arena *arena) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
arena->used_map[i] |= 1 << bit_index;
|
arena->used_map[i] |= 1 << bit_index;
|
||||||
total_arena_gets++;
|
arena->stats.used += 1;
|
||||||
return (char *) arena->objects + (index * arena->object_size);
|
return (char *) arena->objects + (index * arena->object_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +74,6 @@ void *ucl_arena_get(struct ucl_arena *arena) {
|
|||||||
int total_arena_puts = 0;
|
int total_arena_puts = 0;
|
||||||
|
|
||||||
void ucl_arena_put(struct ucl_arena *arena, void *object) {
|
void ucl_arena_put(struct ucl_arena *arena, void *object) {
|
||||||
|
|
||||||
if (object == NULL) {
|
if (object == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -91,10 +87,9 @@ void ucl_arena_put(struct ucl_arena *arena, void *object) {
|
|||||||
assert(index < arena->capacity);
|
assert(index < arena->capacity);
|
||||||
|
|
||||||
assert(arena->used_map[int_index] & (1 << bit_index));
|
assert(arena->used_map[int_index] & (1 << bit_index));
|
||||||
//if (arena->used_map[int_index] & (1 << bit_index)) {
|
total_arena_puts++;
|
||||||
total_arena_puts++;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
arena->used_map[int_index] &= ~(1 << bit_index);
|
arena->used_map[int_index] &= ~(1 << bit_index);
|
||||||
|
arena->stats.used -= 1;
|
||||||
|
arena->stats.freed += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ LISP_FUNC_2(ucl_builtin_nth, state, scope, n, list) {
|
|||||||
UCL_COND_OR_RET_ERROR(n->type == UCL_TYPE_INT, "First argument to nth must be an integer");
|
UCL_COND_OR_RET_ERROR(n->type == UCL_TYPE_INT, "First argument to nth must be an integer");
|
||||||
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "Second argument to nth must be a list");
|
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "Second argument to nth must be a list");
|
||||||
|
|
||||||
return ucl_list_nth(state, list, n->integer);
|
return ucl_list_nth(list, n->integer);
|
||||||
}
|
}
|
||||||
|
|
||||||
LISP_FUNC_2(ucl_builtin_add, state, scope, arg0, arg1) {
|
LISP_FUNC_2(ucl_builtin_add, state, scope, arg0, arg1) {
|
||||||
@@ -272,6 +272,30 @@ LISP_FUNC_2(ucl_builtin_append, state, scope, list, elem) {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_obj_freed, state, scope) {
|
||||||
|
return ucl_int_create(state, state->obj_arena->stats.freed);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_obj_used, state, scope) {
|
||||||
|
return ucl_int_create(state, state->obj_arena->stats.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_obj_remaining, state, scope) {
|
||||||
|
return ucl_int_create(state, state->obj_arena->capacity - state->obj_arena->stats.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_scope_freed, state, scope) {
|
||||||
|
return ucl_int_create(state, state->scope_arena->stats.freed);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_scope_used, state, scope) {
|
||||||
|
return ucl_int_create(state, state->scope_arena->stats.used);
|
||||||
|
}
|
||||||
|
|
||||||
|
LISP_FUNC_0(ucl_builtin_gc_scope_remaining, state, scope) {
|
||||||
|
return ucl_int_create(state, state->scope_arena->capacity - state->scope_arena->stats.used);
|
||||||
|
}
|
||||||
|
|
||||||
void ucl_add_builtin(struct ucl* ucl, const char *name, ucl_lisp fun) {
|
void ucl_add_builtin(struct ucl* ucl, const char *name, ucl_lisp fun) {
|
||||||
ucl_scope_put(ucl, ucl->global_scope, name, ucl_builtin_create(ucl, fun));
|
ucl_scope_put(ucl, ucl->global_scope, name, ucl_builtin_create(ucl, fun));
|
||||||
}
|
}
|
||||||
@@ -316,4 +340,11 @@ void ucl_add_builtins(struct ucl* state) {
|
|||||||
ucl_add_builtin(state, "reduce", ucl_builtin_reduce);
|
ucl_add_builtin(state, "reduce", ucl_builtin_reduce);
|
||||||
ucl_add_builtin(state, "equal", ucl_builtin_equal);
|
ucl_add_builtin(state, "equal", ucl_builtin_equal);
|
||||||
ucl_add_builtin(state, "append", ucl_builtin_append);
|
ucl_add_builtin(state, "append", ucl_builtin_append);
|
||||||
|
|
||||||
|
ucl_add_builtin(state, "gc-obj-used", ucl_builtin_gc_obj_used);
|
||||||
|
ucl_add_builtin(state, "gc-obj-freed", ucl_builtin_gc_obj_freed);
|
||||||
|
ucl_add_builtin(state, "gc-obj-remaining", ucl_builtin_gc_obj_remaining);
|
||||||
|
ucl_add_builtin(state, "gc-scope-used", ucl_builtin_gc_scope_used);
|
||||||
|
ucl_add_builtin(state, "gc-scope-freed", ucl_builtin_gc_scope_freed);
|
||||||
|
ucl_add_builtin(state, "gc-scope-remaining", ucl_builtin_gc_scope_remaining);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ struct ucl_object *ucl_evaluate_builtin_form(struct ucl *state, struct ucl_scope
|
|||||||
struct ucl_object *fun_forms = ucl_cdr(state, fun);
|
struct ucl_object *fun_forms = ucl_cdr(state, fun);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
FOREACH_LIST(fun_arg_syms, iter, sym) {
|
FOREACH_LIST(fun_arg_syms, iter, sym) {
|
||||||
ucl_scope_put(state, fun_scope, sym->symbol, ucl_list_nth(state, evaluated_list, i + 1));
|
ucl_scope_put(state, fun_scope, sym->symbol, ucl_list_nth(evaluated_list, i + 1));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
result = ucl_progn(state, fun_scope, fun_forms);
|
result = ucl_progn(state, fun_scope, fun_forms);
|
||||||
@@ -98,3 +98,7 @@ struct ucl_object *ucl_evaluate_in_scope(struct ucl *state, struct ucl_scope *sc
|
|||||||
struct ucl_object *ucl_evaluate(struct ucl *state, struct ucl_object *obj) {
|
struct ucl_object *ucl_evaluate(struct ucl *state, struct ucl_object *obj) {
|
||||||
return ucl_evaluate_in_scope(state, state->global_scope, obj);
|
return ucl_evaluate_in_scope(state, state->global_scope, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ucl_object *ucl_evaluate_progn(struct ucl *state, struct ucl_object *forms) {
|
||||||
|
return ucl_progn(state, state->global_scope, forms);
|
||||||
|
}
|
||||||
|
|||||||
31
src/lisp.h
31
src/lisp.h
@@ -21,11 +21,8 @@ void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun);
|
|||||||
#define LISP_FUNC_1(func_name, ucl_name, scope_name, arg0_name) \
|
#define LISP_FUNC_1(func_name, ucl_name, scope_name, arg0_name) \
|
||||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name); \
|
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name); \
|
||||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
int len = ucl_list_length_int(args); \
|
||||||
if (len_obj->type != UCL_TYPE_INT) { \
|
if (len != 1) { \
|
||||||
return NULL; \
|
|
||||||
} \
|
|
||||||
if (len_obj->integer != 1) { \
|
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
struct ucl_object *arg0 = ucl_car(ucl, args); \
|
struct ucl_object *arg0 = ucl_car(ucl, args); \
|
||||||
@@ -37,15 +34,12 @@ void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun);
|
|||||||
#define LISP_FUNC_2(func_name, ucl_name, scope_name, arg0_name, arg1_name) \
|
#define LISP_FUNC_2(func_name, ucl_name, scope_name, arg0_name, arg1_name) \
|
||||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name); \
|
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name); \
|
||||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
int len = ucl_list_length_int(args); \
|
||||||
if (len_obj->type != UCL_TYPE_INT) { \
|
if (len != 2) { \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
if (len_obj->integer != 2) { \
|
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
|
||||||
return NULL; \
|
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
|
||||||
} \
|
|
||||||
struct ucl_object *arg0 = ucl_list_nth(ucl, args, 0); \
|
|
||||||
struct ucl_object *arg1 = ucl_list_nth(ucl, args, 1); \
|
|
||||||
return func_name##_impl(ucl, scope, arg0, arg1); \
|
return func_name##_impl(ucl, scope, arg0, arg1); \
|
||||||
} \
|
} \
|
||||||
static struct ucl_object *func_name##_impl(UNUSED struct ucl *ucl_name, UNUSED struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
static struct ucl_object *func_name##_impl(UNUSED struct ucl *ucl_name, UNUSED struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
|
||||||
@@ -54,16 +48,13 @@ void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun);
|
|||||||
#define LISP_FUNC_3(func_name, ucl_name, scope_name, arg0_name, arg1_name, arg2_name) \
|
#define LISP_FUNC_3(func_name, ucl_name, scope_name, arg0_name, arg1_name, arg2_name) \
|
||||||
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name); \
|
static struct ucl_object *func_name##_impl(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name); \
|
||||||
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
struct ucl_object *func_name(struct ucl* ucl, struct ucl_scope *scope, struct ucl_object *args) { \
|
||||||
struct ucl_object *len_obj = ucl_list_length(ucl, args); \
|
int len = ucl_list_length_int(args); \
|
||||||
if (len_obj->type != UCL_TYPE_INT) { \
|
if (len != 3) { \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
if (len_obj->integer != 3) { \
|
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
|
||||||
return NULL; \
|
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
|
||||||
} \
|
struct ucl_object *arg2 = ucl_list_nth(args, 2); \
|
||||||
struct ucl_object *arg0 = ucl_list_nth(ucl, args, 0); \
|
|
||||||
struct ucl_object *arg1 = ucl_list_nth(ucl, args, 1); \
|
|
||||||
struct ucl_object *arg2 = ucl_list_nth(ucl, args, 2); \
|
|
||||||
return func_name##_impl(ucl, scope, arg0, arg1, arg2); \
|
return func_name##_impl(ucl, scope, arg0, arg1, arg2); \
|
||||||
} \
|
} \
|
||||||
static struct ucl_object *func_name##_impl(UNUSED struct ucl* ucl_name, UNUSED struct ucl_scope *scope_name, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name)
|
static struct ucl_object *func_name##_impl(UNUSED struct ucl* ucl_name, UNUSED struct ucl_scope *scope_name, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name)
|
||||||
|
|||||||
10
src/memory.c
10
src/memory.c
@@ -79,6 +79,14 @@ struct ucl_object *ucl_special_create(struct ucl* ucl, ucl_lisp special)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ucl_object_pin(struct ucl_object *obj) {
|
||||||
|
obj->flags |= UCL_OBJ_FLAG_PINNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ucl_object_unpinned(struct ucl_object *obj) {
|
||||||
|
obj->flags &= ~UCL_OBJ_FLAG_PINNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct ucl_object* ucl_object_alloc(struct ucl* ucl) {
|
static struct ucl_object* ucl_object_alloc(struct ucl* ucl) {
|
||||||
struct ucl_object *obj = ucl_arena_get(ucl->obj_arena);
|
struct ucl_object *obj = ucl_arena_get(ucl->obj_arena);
|
||||||
@@ -175,7 +183,7 @@ void ucl_gc(struct ucl* ucl) {
|
|||||||
struct ucl *ucl_create() {
|
struct ucl *ucl_create() {
|
||||||
struct ucl *ucl = malloc(sizeof(*ucl));
|
struct ucl *ucl = malloc(sizeof(*ucl));
|
||||||
|
|
||||||
ucl->obj_arena = ucl_arena_create(sizeof(struct ucl_object), 1 << 16);
|
ucl->obj_arena = ucl_arena_create(sizeof(struct ucl_object), 4096);
|
||||||
ucl->scope_arena = ucl_arena_create(sizeof(struct ucl_scope), 64);
|
ucl->scope_arena = ucl_arena_create(sizeof(struct ucl_scope), 64);
|
||||||
ucl->global_scope = ucl_scope_create(ucl);
|
ucl->global_scope = ucl_scope_create(ucl);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ struct ucl_object *ucl_error_create(struct ucl* ucl, const char* error);
|
|||||||
struct ucl_object *ucl_builtin_create(struct ucl* ucl, ucl_lisp builtin);
|
struct ucl_object *ucl_builtin_create(struct ucl* ucl, ucl_lisp builtin);
|
||||||
struct ucl_object *ucl_special_create(struct ucl* ucl, ucl_lisp special);
|
struct ucl_object *ucl_special_create(struct ucl* ucl, ucl_lisp special);
|
||||||
|
|
||||||
|
void ucl_object_pin(struct ucl_object *obj);
|
||||||
|
void ucl_object_unpin(struct ucl_object *obj);
|
||||||
|
|
||||||
void ucl_object_delete(struct ucl* ucl, struct ucl_object *obj);
|
void ucl_object_delete(struct ucl* ucl, struct ucl_object *obj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
10
src/scope.c
10
src/scope.c
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
#define SCOPE_ARENA_CAPACITY 32
|
#define SCOPE_ARENA_CAPACITY 32
|
||||||
|
|
||||||
static struct ucl_object *ucl_scope_get_cell(struct ucl *state, struct ucl_scope *scope, const char *name) {
|
static struct ucl_object *ucl_scope_get_cell(struct ucl_scope *scope, const char *name) {
|
||||||
FOREACH_LIST(scope->list, iter, item) {
|
FOREACH_LIST(scope->list, iter, item) {
|
||||||
assert(item->type == UCL_TYPE_CELL);
|
assert(item->type == UCL_TYPE_CELL);
|
||||||
const char *item_name = ucl_list_nth(state, item, NAME_POSITION)->string;
|
const char *item_name = ucl_list_nth(item, NAME_POSITION)->string;
|
||||||
if (!strcmp(name, item_name)) {
|
if (!strcmp(name, item_name)) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ static struct ucl_object *ucl_scope_get_cell(struct ucl *state, struct ucl_scope
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *ucl_scope_get(struct ucl *state, struct ucl_scope *scope, const char *name) {
|
struct ucl_object *ucl_scope_get(struct ucl *state, struct ucl_scope *scope, const char *name) {
|
||||||
struct ucl_object *cell = ucl_scope_get_cell(state, scope, name);
|
struct ucl_object *cell = ucl_scope_get_cell(scope, name);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
if (scope->parent == NULL) {
|
if (scope->parent == NULL) {
|
||||||
// TODO: Include the symbol name
|
// TODO: Include the symbol name
|
||||||
@@ -38,11 +38,11 @@ struct ucl_object *ucl_scope_get(struct ucl *state, struct ucl_scope *scope, con
|
|||||||
return ucl_scope_get(state, scope->parent, name);
|
return ucl_scope_get(state, scope->parent, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ucl_list_nth(state, cell, DATA_POSITION);
|
return ucl_list_nth(cell, DATA_POSITION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ucl_scope_put(struct ucl *state, struct ucl_scope *scope, const char *name, struct ucl_object *obj) {
|
void ucl_scope_put(struct ucl *state, struct ucl_scope *scope, const char *name, struct ucl_object *obj) {
|
||||||
struct ucl_object *cell = ucl_scope_get_cell(state, scope, name);
|
struct ucl_object *cell = ucl_scope_get_cell(scope, name);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
ucl_list_append(state,
|
ucl_list_append(state,
|
||||||
scope->list,
|
scope->list,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct ucl_object *ucl_special_let(struct ucl *state, struct ucl_scope *scope, s
|
|||||||
struct ucl_object *ucl_special_if(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
struct ucl_object *ucl_special_if(struct ucl *state, struct ucl_scope *scope, struct ucl_object *args) {
|
||||||
// TODO: Check arguments
|
// TODO: Check arguments
|
||||||
struct ucl_object *cond = ucl_car(state, args);
|
struct ucl_object *cond = ucl_car(state, args);
|
||||||
struct ucl_object *true_form = ucl_list_nth(state, args, 1);
|
struct ucl_object *true_form = ucl_list_nth(args, 1);
|
||||||
struct ucl_object *false_forms = ucl_cdr(state, ucl_cdr(state, args));
|
struct ucl_object *false_forms = ucl_cdr(state, ucl_cdr(state, args));
|
||||||
|
|
||||||
struct ucl_object *cond_result = ucl_evaluate_in_scope(state, scope, cond);
|
struct ucl_object *cond_result = ucl_evaluate_in_scope(state, scope, cond);
|
||||||
@@ -57,7 +57,7 @@ struct ucl_object *ucl_special_defun(struct ucl *state, struct ucl_scope *scope,
|
|||||||
return ucl_error_create(state, "First argument to defun must be a symbol");
|
return ucl_error_create(state, "First argument to defun must be a symbol");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *fun_args = ucl_list_nth(state, args, 1);
|
struct ucl_object *fun_args = ucl_list_nth(args, 1);
|
||||||
if (fun_args->type != UCL_TYPE_CELL) {
|
if (fun_args->type != UCL_TYPE_CELL) {
|
||||||
// TODO: Check that the list contains only symbols
|
// TODO: Check that the list contains only symbols
|
||||||
return ucl_error_create(state, "Second argument to defun must be a list of symbols");
|
return ucl_error_create(state, "Second argument to defun must be a list of symbols");
|
||||||
@@ -75,7 +75,7 @@ struct ucl_object *ucl_special_defun(struct ucl *state, struct ucl_scope *scope,
|
|||||||
|
|
||||||
struct ucl_object *ucl_special_lambda(struct ucl *state, UNUSED struct ucl_scope *scope, struct ucl_object *args) {
|
struct ucl_object *ucl_special_lambda(struct ucl *state, UNUSED struct ucl_scope *scope, struct ucl_object *args) {
|
||||||
// TODO: Check arguments
|
// TODO: Check arguments
|
||||||
struct ucl_object *fun_args = ucl_list_nth(state, args, 0);
|
struct ucl_object *fun_args = ucl_list_nth(args, 0);
|
||||||
if (fun_args->type != UCL_TYPE_CELL) {
|
if (fun_args->type != UCL_TYPE_CELL) {
|
||||||
// TODO: Check that the list contains only symbols
|
// TODO: Check that the list contains only symbols
|
||||||
return ucl_error_create(state, "First argument to lambda must be a list of symbols");
|
return ucl_error_create(state, "First argument to lambda must be a list of symbols");
|
||||||
@@ -90,19 +90,27 @@ struct ucl_object *ucl_special_dotimes(struct ucl *state, struct ucl_scope *scop
|
|||||||
struct ucl_object *body = ucl_cdr(state, args);
|
struct ucl_object *body = ucl_cdr(state, args);
|
||||||
|
|
||||||
struct ucl_object *var = ucl_car(state, assignment);
|
struct ucl_object *var = ucl_car(state, assignment);
|
||||||
struct ucl_object *times = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, assignment, 1));
|
struct ucl_object *times = ucl_evaluate_in_scope(state, scope, ucl_list_nth(assignment, 1));
|
||||||
|
|
||||||
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dotimes must be an symbol");
|
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dotimes must be an symbol");
|
||||||
UCL_COND_OR_RET_ERROR(times->type == UCL_TYPE_INT, "'times' argument to dotimes must be an int");
|
UCL_COND_OR_RET_ERROR(times->type == UCL_TYPE_INT, "'times' argument to dotimes must be an int");
|
||||||
|
|
||||||
struct ucl_scope *let_scope = ucl_scope_create_child(state, scope);
|
struct ucl_scope *let_scope = ucl_scope_create_child(state, scope);
|
||||||
|
|
||||||
|
struct ucl_object *iter = ucl_int_create(state, 0);
|
||||||
|
ucl_scope_put(state, let_scope, var->symbol, var);
|
||||||
|
|
||||||
for (int i = 0; i < times->integer; i++) {
|
for (int i = 0; i < times->integer; i++) {
|
||||||
ucl_scope_put(state, let_scope, var->symbol, ucl_int_create(state, i));
|
iter->integer = i;
|
||||||
struct ucl_object *iterval = ucl_progn(state, let_scope, body);
|
struct ucl_object *iterval = ucl_progn(state, let_scope, body);
|
||||||
UCL_RET_IF_ERROR(iterval);
|
UCL_RET_IF_ERROR(iterval);
|
||||||
|
// TODO: don't make this an error, just rebind?
|
||||||
|
/* UCL_COND_OR_RET_ERROR(ucl_scope_get(state, let_scope, var->symbol)->type == UCL_TYPE_INT, */
|
||||||
|
/* "dotimes iterator was re-bound to a non-integer type"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: cleanup scopes on error
|
||||||
|
ucl_scope_delete(state, let_scope);
|
||||||
return ucl_nil_create(state);
|
return ucl_nil_create(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +120,7 @@ struct ucl_object *ucl_special_dolist(struct ucl *state, struct ucl_scope *scope
|
|||||||
struct ucl_object *body = ucl_cdr(state, args);
|
struct ucl_object *body = ucl_cdr(state, args);
|
||||||
|
|
||||||
struct ucl_object *var = ucl_car(state, assignment);
|
struct ucl_object *var = ucl_car(state, assignment);
|
||||||
struct ucl_object *list = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, assignment, 1));
|
struct ucl_object *list = ucl_evaluate_in_scope(state, scope, ucl_list_nth(assignment, 1));
|
||||||
|
|
||||||
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dolist must be an symbol");
|
UCL_COND_OR_RET_ERROR(var->type == UCL_TYPE_SYMBOL, "'var' argument to dolist must be an symbol");
|
||||||
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "'list' argument to dolist must be a list");
|
UCL_COND_OR_RET_ERROR(list->type == UCL_TYPE_CELL, "'list' argument to dolist must be a list");
|
||||||
@@ -128,6 +136,8 @@ struct ucl_object *ucl_special_dolist(struct ucl *state, struct ucl_scope *scope
|
|||||||
UCL_RET_IF_ERROR(iterval);
|
UCL_RET_IF_ERROR(iterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: cleanup scopes on error
|
||||||
|
ucl_scope_delete(state, let_scope);
|
||||||
return ucl_nil_create(state);
|
return ucl_nil_create(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +165,7 @@ struct ucl_object *ucl_special_setq(struct ucl *state, struct ucl_scope *scope,
|
|||||||
return ucl_error_create(state, "First argument to setq must be a symbol");
|
return ucl_error_create(state, "First argument to setq must be a symbol");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *value = ucl_evaluate_in_scope(state, scope, ucl_list_nth(state, args, 1));
|
struct ucl_object *value = ucl_evaluate_in_scope(state, scope, ucl_list_nth(args, 1));
|
||||||
UCL_RET_IF_ERROR(value);
|
UCL_RET_IF_ERROR(value);
|
||||||
|
|
||||||
ucl_scope_put(state, scope, sym->symbol, value);
|
ucl_scope_put(state, scope, sym->symbol, value);
|
||||||
|
|||||||
14
src/types.h
14
src/types.h
@@ -1,6 +1,8 @@
|
|||||||
#ifndef _UCLISP_TYPES_H_
|
#ifndef _UCLISP_TYPES_H_
|
||||||
#define _UCLISP_TYPES_H_
|
#define _UCLISP_TYPES_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
struct ucl;
|
struct ucl;
|
||||||
struct ucl_scope;
|
struct ucl_scope;
|
||||||
struct ucl_cell;
|
struct ucl_cell;
|
||||||
@@ -48,6 +50,18 @@ struct ucl_scope {
|
|||||||
struct ucl_scope *parent;
|
struct ucl_scope *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ucl_arena {
|
||||||
|
size_t object_size;
|
||||||
|
size_t capacity;
|
||||||
|
void *objects;
|
||||||
|
int *used_map;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
size_t used;
|
||||||
|
size_t freed;
|
||||||
|
} stats;
|
||||||
|
};
|
||||||
|
|
||||||
struct ucl {
|
struct ucl {
|
||||||
struct ucl_scope *global_scope;
|
struct ucl_scope *global_scope;
|
||||||
|
|
||||||
|
|||||||
@@ -52,31 +52,41 @@ struct ucl_object *ucl_predicate(struct ucl* state, bool value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *ucl_list_length(struct ucl *state, struct ucl_object *list) {
|
int ucl_list_length_int(struct ucl_object *list) {
|
||||||
UCL_COND_OR_RET_ERROR(
|
if (list == NULL || list->type != UCL_TYPE_CELL) {
|
||||||
list != NULL && list->type == UCL_TYPE_CELL,
|
return -1;
|
||||||
"Invalid type of argument 0 to 'ucl_list_length'");
|
|
||||||
|
|
||||||
struct ucl_object *node = list;
|
|
||||||
if (list->cell.car == NULL) {
|
|
||||||
return ucl_int_create(state, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list->cell.car == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_object *node = list;
|
||||||
int length = 1;
|
int length = 1;
|
||||||
while (node->cell.cdr != NULL) {
|
while (node->cell.cdr != NULL) {
|
||||||
node = node->cell.cdr;
|
node = node->cell.cdr;
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_object *ucl_list_length(struct ucl *state, struct ucl_object *list) {
|
||||||
|
int length = ucl_list_length_int(list);
|
||||||
|
|
||||||
|
UCL_COND_OR_RET_ERROR(
|
||||||
|
length >= 0,
|
||||||
|
"Invalid type of argument 0 to 'ucl_list_length'");
|
||||||
|
|
||||||
return ucl_int_create(state, length);
|
return ucl_int_create(state, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ucl_object *ucl_list_nth(struct ucl *state, struct ucl_object *list, int n) {
|
struct ucl_object *ucl_list_nth(struct ucl_object *list, int n) {
|
||||||
UCL_COND_OR_RET_ERROR(
|
UCL_COND_OR_RET_ERROR(
|
||||||
list != NULL && list->type == UCL_TYPE_CELL,
|
list != NULL && list->type == UCL_TYPE_CELL,
|
||||||
"Invalid type of argument 0 to 'ucl_list_nth'");
|
"Invalid type of argument 0 to 'ucl_list_nth'");
|
||||||
|
|
||||||
int length = ucl_list_length(state, list)->integer;
|
int length = ucl_list_length_int(list);
|
||||||
UCL_COND_OR_RET_ERROR(length > n, "Position n >= list length in ucl_list_nth");
|
UCL_COND_OR_RET_ERROR(length > n, "Position n >= list length in ucl_list_nth");
|
||||||
UCL_COND_OR_RET_ERROR(n >= 0, "Index to ucl_list_nth was less that zero");
|
UCL_COND_OR_RET_ERROR(n >= 0, "Index to ucl_list_nth was less that zero");
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,14 @@ struct ucl_object *ucl_equal(struct ucl* state, struct ucl_object *arg0, struct
|
|||||||
struct ucl_object* ucl_car(struct ucl* state, struct ucl_object *list);
|
struct ucl_object* ucl_car(struct ucl* state, struct ucl_object *list);
|
||||||
struct ucl_object* ucl_cdr(struct ucl* state, struct ucl_object *list);
|
struct ucl_object* ucl_cdr(struct ucl* state, struct ucl_object *list);
|
||||||
|
|
||||||
|
int ucl_list_length_int(struct ucl_object *list);
|
||||||
struct ucl_object* ucl_list_length(struct ucl* state, struct ucl_object *list);
|
struct ucl_object* ucl_list_length(struct ucl* state, struct ucl_object *list);
|
||||||
struct ucl_object* ucl_list_nth(struct ucl* state, struct ucl_object *list, int n);
|
struct ucl_object* ucl_list_nth(struct ucl_object *list, int n);
|
||||||
struct ucl_object* ucl_list_append(struct ucl* state, struct ucl_object *list, struct ucl_object *obj);
|
struct ucl_object* ucl_list_append(struct ucl* state, struct ucl_object *list, struct ucl_object *obj);
|
||||||
struct ucl_object* ucl_tuple_create(struct ucl* state, struct ucl_object *obj0, struct ucl_object *obj1);
|
struct ucl_object* ucl_tuple_create(struct ucl* state, struct ucl_object *obj0, struct ucl_object *obj1);
|
||||||
|
|
||||||
struct ucl_object *ucl_progn(struct ucl* state, struct ucl_scope *scope, struct ucl_object *forms);
|
struct ucl_object *ucl_progn(struct ucl* state, struct ucl_scope *scope, struct ucl_object *forms);
|
||||||
|
|
||||||
void ucl_print_obj(struct ucl_object *obj);
|
|
||||||
|
|
||||||
struct ucl_object* ucl_evaluate_in_scope(struct ucl *state, struct ucl_scope *scope, struct ucl_object* sexp);
|
struct ucl_object* ucl_evaluate_in_scope(struct ucl *state, struct ucl_scope *scope, struct ucl_object* sexp);
|
||||||
|
|
||||||
void ucl_add_builtins(struct ucl *state);
|
void ucl_add_builtins(struct ucl *state);
|
||||||
|
|||||||
@@ -225,6 +225,36 @@ void test_complex(void) {
|
|||||||
TEST_ASSERT_OBJ_INT_V(response, 9);
|
TEST_ASSERT_OBJ_INT_V(response, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_memory_perf_low(void) {
|
||||||
|
response = eval("(defun fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "fib");
|
||||||
|
|
||||||
|
response = eval("(fib 4)");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_INT_V(response, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_memory_perf_medium(void) {
|
||||||
|
response = eval("(defun fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "fib");
|
||||||
|
|
||||||
|
response = eval("(fib 10)");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_INT_V(response, 55);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_memory_perf_high(void) {
|
||||||
|
response = eval("(defun fib (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_SYMBOL_V(response, "fib");
|
||||||
|
|
||||||
|
response = eval("(fib 8)");
|
||||||
|
|
||||||
|
TEST_ASSERT_OBJ_INT_V(response, 21);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
|
|
||||||
@@ -254,6 +284,9 @@ int main(void) {
|
|||||||
RUN_TEST(test_nth_oob);
|
RUN_TEST(test_nth_oob);
|
||||||
RUN_TEST(test_eval_defun_gc);
|
RUN_TEST(test_eval_defun_gc);
|
||||||
RUN_TEST(test_complex);
|
RUN_TEST(test_complex);
|
||||||
|
RUN_TEST(test_memory_perf_low);
|
||||||
|
RUN_TEST(test_memory_perf_medium);
|
||||||
|
RUN_TEST(test_memory_perf_high);
|
||||||
|
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ static void test_put_modify_get(void) {
|
|||||||
ucl_list_append(state, obj, ucl_string_create(state, "quux"));
|
ucl_list_append(state, obj, ucl_string_create(state, "quux"));
|
||||||
response = ucl_scope_get(state, scope, "foo");
|
response = ucl_scope_get(state, scope, "foo");
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(state, response, 2));
|
TEST_ASSERT_OBJ_STRING(ucl_list_nth(response, 2));
|
||||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(state, response, 2)->string, "quux");
|
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(response, 2)->string, "quux");
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_STRING(ucl_list_nth(state, obj, 2));
|
TEST_ASSERT_OBJ_STRING(ucl_list_nth(obj, 2));
|
||||||
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(state, obj, 2)->string, "quux");
|
TEST_ASSERT_EQUAL_STRING(ucl_list_nth(obj, 2)->string, "quux");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -134,20 +134,19 @@ static void test_list_append_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_nil_0() {
|
static void test_list_nth_nil_0() {
|
||||||
response = ucl_list_nth(state, ucl_nil_create(state), 0);
|
response = ucl_list_nth(ucl_nil_create(state), 0);
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_ERROR(response);
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_nil_1() {
|
static void test_list_nth_nil_1() {
|
||||||
response = ucl_list_nth(state, ucl_nil_create(state), 1);
|
response = ucl_list_nth(ucl_nil_create(state), 1);
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_ERROR(response);
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_list_0() {
|
static void test_list_nth_list_0() {
|
||||||
response = ucl_list_nth(
|
response = ucl_list_nth(
|
||||||
state,
|
|
||||||
ucl_tuple_create(state,
|
ucl_tuple_create(state,
|
||||||
ucl_t_create(state),
|
ucl_t_create(state),
|
||||||
ucl_string_create(state, "foo")),
|
ucl_string_create(state, "foo")),
|
||||||
@@ -158,7 +157,6 @@ static void test_list_nth_list_0() {
|
|||||||
|
|
||||||
static void test_list_nth_list_1() {
|
static void test_list_nth_list_1() {
|
||||||
response = ucl_list_nth(
|
response = ucl_list_nth(
|
||||||
state,
|
|
||||||
ucl_tuple_create(state,
|
ucl_tuple_create(state,
|
||||||
ucl_t_create(state),
|
ucl_t_create(state),
|
||||||
ucl_string_create(state, "foo")),
|
ucl_string_create(state, "foo")),
|
||||||
@@ -168,20 +166,19 @@ static void test_list_nth_list_1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_t_0() {
|
static void test_list_nth_t_0() {
|
||||||
response = ucl_list_nth(state, ucl_t_create(state), 1);
|
response = ucl_list_nth(ucl_t_create(state), 1);
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_ERROR(response);
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_bounds_0() {
|
static void test_list_nth_bounds_0() {
|
||||||
response = ucl_list_nth(state, ucl_nil_create(state), 0);
|
response = ucl_list_nth(ucl_nil_create(state), 0);
|
||||||
|
|
||||||
TEST_ASSERT_OBJ_ERROR(response);
|
TEST_ASSERT_OBJ_ERROR(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_list_nth_bounds_1() {
|
static void test_list_nth_bounds_1() {
|
||||||
response = ucl_list_nth(
|
response = ucl_list_nth(
|
||||||
state,
|
|
||||||
ucl_cell_create(state,
|
ucl_cell_create(state,
|
||||||
ucl_nil_create(state),
|
ucl_nil_create(state),
|
||||||
NULL),
|
NULL),
|
||||||
@@ -192,7 +189,6 @@ static void test_list_nth_bounds_1() {
|
|||||||
|
|
||||||
static void test_list_nth_bounds_2() {
|
static void test_list_nth_bounds_2() {
|
||||||
response = ucl_list_nth(
|
response = ucl_list_nth(
|
||||||
state,
|
|
||||||
ucl_tuple_create(state,
|
ucl_tuple_create(state,
|
||||||
ucl_nil_create(state),
|
ucl_nil_create(state),
|
||||||
ucl_nil_create(state)),
|
ucl_nil_create(state)),
|
||||||
|
|||||||
@@ -40,21 +40,24 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define TEST_ASSERT_OBJ_LIST(obj) \
|
#define TEST_ASSERT_OBJ_LIST(obj) \
|
||||||
TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_CELL, obj->type, "Expected cell type")
|
TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_CELL, (obj)->type, "Expected cell type")
|
||||||
|
|
||||||
#define TEST_ASSERT_LIST_LEN(list, len) \
|
#define TEST_ASSERT_LIST_LEN(list, len) \
|
||||||
do { \
|
do { \
|
||||||
TEST_ASSERT_OBJ_LIST(list); \
|
TEST_ASSERT_OBJ_LIST(list); \
|
||||||
TEST_ASSERT_EQUAL(len, ucl_list_length(state, list)->integer); \
|
TEST_ASSERT_EQUAL_MESSAGE(len, ucl_list_length(state, list)->integer, "Unexpected list length"); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define TEST_ASSERT_NIL(obj) \
|
#define TEST_ASSERT_NIL(obj) \
|
||||||
TEST_ASSERT_LIST_LEN(obj, 0)
|
do { \
|
||||||
|
TEST_ASSERT_OBJ_LIST(obj); \
|
||||||
|
TEST_ASSERT_LIST_LEN(obj, 0); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define TEST_ASSERT_T(obj) \
|
#define TEST_ASSERT_T(obj) \
|
||||||
do { \
|
do { \
|
||||||
TEST_ASSERT_OBJ_SYMBOL(obj); \
|
TEST_ASSERT_OBJ_SYMBOL(obj); \
|
||||||
TEST_ASSERT_EQUAL_STRING(obj->symbol, "t"); \
|
TEST_ASSERT_EQUAL_STRING((obj)->symbol, "t"); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user