|
|
@ -21,6 +21,9 @@ |
|
|
|
#define _KEYWORD_INK_END "end" |
|
|
|
#define _KEYWORD_INK_RETURN "return" |
|
|
|
|
|
|
|
#define min(x, y) ((x) > (y) ? (y) : (x)) |
|
|
|
#define max(x, y) ((x) < (y) ? (y) : (x)) |
|
|
|
|
|
|
|
struct label { |
|
|
|
int active; |
|
|
|
int dest; |
|
|
@ -271,6 +274,9 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, |
|
|
|
ctx->routines = NULL; |
|
|
|
ctx->routines_capacity = 0; |
|
|
|
ctx->routines_top = 0; |
|
|
|
ctx->types = NULL; |
|
|
|
ctx->types_capacity = 0; |
|
|
|
ctx->types_top = 0; |
|
|
|
ctx->native_words = NULL; |
|
|
|
ctx->native_words_capacity = 0; |
|
|
|
ctx->native_words_top = 0; |
|
|
@ -280,7 +286,8 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, |
|
|
|
ctx->lex_reserved_words = NULL; |
|
|
|
ctx->lex_reserved_words_capacity = 0; |
|
|
|
ctx->lex_reserved_words_top = 0; |
|
|
|
ctx->steps = 0; |
|
|
|
ctx->collections = 0; |
|
|
|
ctx->steps = 0; |
|
|
|
return ctx; |
|
|
|
} |
|
|
|
|
|
|
@ -791,6 +798,172 @@ int ink_step_everyone(struct context* pContext) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int ink_new_type( |
|
|
|
struct context* ctx, |
|
|
|
const char* type_name, |
|
|
|
int size, |
|
|
|
void (*collect)(struct context*,void*), |
|
|
|
struct ink_collection_list (*gc)(struct context*,void*) |
|
|
|
) { |
|
|
|
if(ctx->panic) return -128; |
|
|
|
if(ctx->types == NULL) { |
|
|
|
ctx->types = ctx->inner_malloc(sizeof(struct ink_type) * 8); |
|
|
|
ctx->types_top = 0; |
|
|
|
ctx->types_capacity = 8; |
|
|
|
} else if(ctx->types_top == ctx->types_capacity) { |
|
|
|
int new_count = (ctx->types_capacity + ctx->types_capacity/2); |
|
|
|
void* renewed = ctx->inner_realloc(ctx->types, sizeof(struct ink_type) * new_count); |
|
|
|
if(renewed == NULL) { |
|
|
|
return -129; |
|
|
|
} else { |
|
|
|
ctx->types = renewed; |
|
|
|
ctx->types_capacity = new_count; |
|
|
|
} |
|
|
|
} |
|
|
|
ctx->types[ctx->types_top].name = type_name; |
|
|
|
ctx->types[ctx->types_top].element_size = size; |
|
|
|
ctx->types[ctx->types_top].elements = NULL; |
|
|
|
ctx->types[ctx->types_top].elements_top = 0; |
|
|
|
ctx->types[ctx->types_top].elements_capacity = 0; |
|
|
|
ctx->types[ctx->types_top].collect = collect; |
|
|
|
ctx->types[ctx->types_top].gc = gc; |
|
|
|
|
|
|
|
ctx->types_top++; |
|
|
|
// Satisfying the minimal value requirement |
|
|
|
return ctx->types_top - 1 + 16; |
|
|
|
} |
|
|
|
|
|
|
|
static struct element_slab* ink_get_value_link(struct context* ctx, struct elem ref) { |
|
|
|
if(ref.type < 16) return NULL; |
|
|
|
int type_id = ref.type - 16; |
|
|
|
if(type_id >= ctx->types_top) return NULL; |
|
|
|
if(ctx->types[type_id].element_size == 0) return NULL; |
|
|
|
if(ref.value < 0) return NULL; |
|
|
|
if(ref.value >= ctx->types[type_id].elements_top) return NULL; |
|
|
|
if(! ctx->types[type_id].elements[ref.value].in_use) return NULL; |
|
|
|
return ctx->types[type_id].elements + ref.value; |
|
|
|
} |
|
|
|
|
|
|
|
void* ink_get_value(struct context* ctx, struct elem ref) { |
|
|
|
struct element_slab* s; |
|
|
|
s = ink_get_value_link(ctx, ref); |
|
|
|
if(s == NULL) return NULL; |
|
|
|
return s->data; |
|
|
|
} |
|
|
|
|
|
|
|
struct elem ink_make_native(struct context* ctx, int type, void* ptr) { |
|
|
|
if(type < 16) { |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -130; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
int type_id = type - 16; |
|
|
|
if(type_id >= ctx->types_top) { |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -129; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
if(ctx->panic) { |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -135; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
if(ctx->types[type_id].elements == NULL) { |
|
|
|
ctx->types[type_id].elements = ctx->inner_malloc(sizeof(struct element_slab) * 8); |
|
|
|
ctx->types[type_id].elements_top = 0; |
|
|
|
ctx->types[type_id].elements_capacity = 8; |
|
|
|
memset(ctx->types[type_id].elements + ctx->types[type_id].elements_top, 0, ctx->types[type_id].elements_capacity - ctx->types[type_id].elements_top); |
|
|
|
} else if(ctx->types[type_id].elements_top == ctx->types[type_id].elements_capacity) { |
|
|
|
int new_count = (ctx->types[type_id].elements_capacity + ctx->types[type_id].elements_capacity/2); |
|
|
|
void* renewed = ctx->inner_realloc(ctx->types[type_id].elements, sizeof(struct element_slab) * new_count); |
|
|
|
if(renewed == NULL) { |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -129; |
|
|
|
return ret; |
|
|
|
} else { |
|
|
|
ctx->types[type_id].elements = renewed; |
|
|
|
ctx->types[type_id].elements_capacity = new_count; |
|
|
|
memset(ctx->types[type_id].elements + ctx->types[type_id].elements_top, 0, ctx->types[type_id].elements_capacity - ctx->types[type_id].elements_top); |
|
|
|
} |
|
|
|
} |
|
|
|
int g = ctx->types[type_id].elements_capacity; |
|
|
|
int i; |
|
|
|
for(i = 0; i < g; ++i) { |
|
|
|
if(! ctx->types[type_id].elements[i].in_use) { |
|
|
|
ctx->types[type_id].elements[i].in_use = 1; |
|
|
|
ctx->types[type_id].elements[i].uses = 1; |
|
|
|
if(ctx->types[type_id].element_size < 0) { |
|
|
|
ctx->types[type_id].elements[i].data = ptr; |
|
|
|
} else { |
|
|
|
void* new_ptr = ctx->malloc(ctx->types[type_id].element_size); |
|
|
|
if(new_ptr == NULL) { |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -139; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
memcpy(new_ptr, ptr, ctx->types[type_id].element_size); |
|
|
|
ctx->types[type_id].elements[i].data = ptr; |
|
|
|
} |
|
|
|
ctx->types[type_id].elements_top = max(ctx->types[type_id].elements_top+1, i+1); |
|
|
|
struct elem ret; |
|
|
|
ret.type = type; |
|
|
|
ret.value = i; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
struct elem ret; |
|
|
|
ret.type = 0; |
|
|
|
ret.value = -140; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
void ink_gc(struct context* ctx) { |
|
|
|
int i, j, k; |
|
|
|
for(i = 0; i < ctx->types_top; ++i) { |
|
|
|
for(j = 0; j < ctx->types[i].elements_top; ++j) { |
|
|
|
ctx->types[i].elements[j].uses = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for(i = 0; i < ctx->types_top; ++i) { |
|
|
|
for(j = 0; j < ctx->types[i].elements_top; ++j) { |
|
|
|
struct ink_collection_list c = ctx->types[i].gc(ctx, ctx->types[i].elements[j].data); |
|
|
|
for(k = 0; k < c.count; ++k) { |
|
|
|
struct element_slab* v = ink_get_value_link(ctx, c.elements[k]); |
|
|
|
if(v != NULL) ++v->uses; |
|
|
|
} |
|
|
|
if(c.elements != NULL) ctx->inner_free(c.elements); |
|
|
|
} |
|
|
|
} |
|
|
|
for(i = 0; i < ctx->routines_top; ++i) { |
|
|
|
for(j = 0; j < ctx->routines[i].top; ++j) { |
|
|
|
struct element_slab* v = ink_get_value_link(ctx, ctx->routines[i].stack[j]); |
|
|
|
if(v != NULL) ++v->uses; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for(i = 0; i < ctx->types_top; ++i) { |
|
|
|
for(j = 0; j < ctx->types[i].elements_top; ++j) { |
|
|
|
if(ctx->types[i].elements[j].uses == 0) { |
|
|
|
ctx->collections++; |
|
|
|
ctx->types[i].collect(ctx, ctx->types[i].elements[j].data); |
|
|
|
if(ctx->types[i].element_size > 0) { |
|
|
|
ctx->free(ctx->types[i].elements[j].data); |
|
|
|
} |
|
|
|
ctx->types[i].elements[j].data = NULL; |
|
|
|
ctx->types[i].elements[j].uses = 0; |
|
|
|
ctx->types[i].elements[j].in_use = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/**********************************************************************************************************************/ |
|
|
|
|
|
|
|
static void print_stacktrace(struct context* _) { |
|
|
@ -1069,10 +1242,54 @@ static void print_as_utf8(struct context* ctx) { |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
struct ink_array { |
|
|
|
int top; |
|
|
|
int capacity; |
|
|
|
struct elem* elements; |
|
|
|
}; |
|
|
|
|
|
|
|
static int get_type_by_name(struct context* ctx, const char* name) { |
|
|
|
int i; |
|
|
|
for(i = 0; i < ctx->types_top; ++i) { |
|
|
|
if(strcmp(ctx->types[i].name, name) == 0) { |
|
|
|
return i + 16; |
|
|
|
} |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static void collect_array(struct context* ctx, void* array) { |
|
|
|
struct ink_array* ary = array; |
|
|
|
ctx->free(ary->elements); |
|
|
|
} |
|
|
|
|
|
|
|
static struct ink_collection_list gc_array(struct context* ctx, void* array) { |
|
|
|
struct ink_array* ary = array; |
|
|
|
struct ink_collection_list c; |
|
|
|
c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); |
|
|
|
c.count = ary->top; |
|
|
|
memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); |
|
|
|
return c; |
|
|
|
} |
|
|
|
|
|
|
|
static void new_array(struct context* ctx) { |
|
|
|
int tid = get_type_by_name(ctx, "array"); |
|
|
|
struct ink_array ary; |
|
|
|
ary.elements = NULL; |
|
|
|
ary.top = 0; |
|
|
|
ary.capacity = 0; |
|
|
|
struct elem e = ink_make_native(ctx, tid, &ary); |
|
|
|
ink_push(ctx, e); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ink_std_library(struct context* ctx) { |
|
|
|
int v; |
|
|
|
v = 0; |
|
|
|
v += ink_add_native(ctx, "trace", print_stacktrace); |
|
|
|
int array_t = ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array); |
|
|
|
v += ink_add_native(ctx, "array", new_array); |
|
|
|
v += ink_add_native(ctx, "trace", print_stacktrace); |
|
|
|
v += ink_add_native(ctx, "print_int", print_int); |
|
|
|
v += ink_add_native(ctx, "print_utf8", print_as_utf8); |
|
|
|
v += ink_add_native(ctx, "+", add_int); |
|
|
|