Ludovic 'Archivist' Lagouardette 1 week ago
parent
commit
fcb3457788
3 changed files with 146 additions and 86 deletions
  1. +3
    -0
      README.md
  2. +20
    -9
      include/ink.h
  3. +123
    -77
      lib.c

+ 3
- 0
README.md View File

@ -11,6 +11,9 @@ It is fully self-contained and doesn't rely on a working standard library beyond
- `free`
- `putchar`
These functions need to be wrapped, the wrapper allows to make them stateful to keep individual heaps per context,
allowing to clean the context by cleaning up its allocations.
To make the library not use the standard library, build it with `NOSTDLIB` defined as a preprocessor directive.
All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. I added a

+ 20
- 9
include/ink.h View File

@ -138,14 +138,14 @@ struct ink_type {
struct context {
int panic;
void *(*inner_malloc)(size_t);
void *(*inner_realloc)(void *, size_t);
void (*inner_free)(void *);
void *(*malloc)(size_t);
void *(*realloc)(void *, size_t);
void (*free)(void *);
int (*putchar)(int);
void *(*inner_malloc)(k">struct context*,size_t);
void *(*inner_realloc)(">struct context*,void *, size_t);
void (*inner_free)(">struct context*,void *);
void *(*malloc)(k">struct context*,size_t);
void *(*realloc)(">struct context*,void *, size_t);
void (*free)(">struct context*,void *);
int (*putchar)(">struct context*,int);
struct ink_routine *routines;
int routines_capacity;
@ -230,7 +230,18 @@ int ink_push_fn(struct context *ctx, struct stack_frame value);
* @param putchar a function to print to the output character by character
* @return a pointer to a context allocated within the malloc function itself.
*/
struct context* ink_make_context(void *(*malloc)(size_t), void *(*realloc)(void *, size_t), void(*free)(void *), int(*putchar)(int));
struct context* ink_make_context(void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int));
/**
* Create a context to execute routines in-place
* @param location a pointer to where the context should be built, userdata can be set in advance
* @param malloc the memory allocation function, with a signature similar to the standard malloc
* @param realloc the memory allocation function, with a signature similar to the standard realloc
* @param free the memory allocation function, with a signature similar to the standard free
* @param putchar a function to print to the output character by character
* @return a pointer to a context allocated within the malloc function itself.
*/
void ink_make_context_inplace(struct context* location, void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int));
#ifndef NOSTDLIB
/**

+ 123
- 77
lib.c View File

@ -116,14 +116,14 @@ int ink_add_native(struct context* ctx, const char* name, void(*value)(struct co
int len;
char* copy;
if(ctx->native_words == NULL) {
ctx->native_words = ctx->inner_malloc(sizeof(struct native_fn) * 8);
ctx->native_words = ctx->inner_malloc(n">ctx, sizeof(struct native_fn) * 8);
ctx->native_words_top = 0;
ctx->native_words_capacity = 8;
} else if(ctx->native_words_top == ctx->native_words_capacity) {
int new_count;
void* renewed;
new_count = (ctx->native_words_capacity + ctx->native_words_capacity/2);
renewed = ctx->inner_realloc(ctx->native_words, sizeof(struct native_fn) * new_count);
renewed = ctx->inner_realloc(ctxp">, ctx->native_words, sizeof(struct native_fn) * new_count);
if(renewed == NULL) {
return -3;
} else {
@ -132,7 +132,7 @@ int ink_add_native(struct context* ctx, const char* name, void(*value)(struct co
}
}
len = strlen(name);
copy = ctx->inner_malloc(len+1);
copy = ctx->inner_malloc(ctx, len+1);
if(copy == NULL) {
return -4;
}
@ -149,14 +149,14 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem
char* copy;
if(ctx->words == NULL) {
ctx->words = ctx->malloc(sizeof(struct fn) * 8);
ctx->words = ctx->malloc(n">ctx, sizeof(struct fn) * 8);
ctx->words_top = 0;
ctx->words_capacity = 8;
} else if(ctx->words_top == ctx->words_capacity) {
int new_count;
void* renewed;
new_count = (ctx->words_capacity + ctx->words_capacity/2);
renewed = ctx->realloc(ctx->words, sizeof(struct fn) * new_count);
renewed = ctx->realloc(ctxp">, ctx->words, sizeof(struct fn) * new_count);
if(renewed == NULL) {
return -1;
} else {
@ -166,21 +166,21 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem
}
for(i = 0; i < ctx->words_top; ++i) {
if(strcmp(name, ctx->words[i].name) == 0) {
ctx->free(ctx->words[i].things);
ctx->words[i].things = ctx->malloc(sizeof(struct elem) * count);
ctx->free(ctxp">, ctx->words[i].things);
ctx->words[i].things = ctx->malloc(n">ctx, sizeof(struct elem) * count);
memcpy(ctx->words[i].things, m, sizeof(struct elem) * count);
ctx->words[i].size = count;
return i;
}
}
len = strlen(name);
copy = ctx->malloc(len+1);
copy = ctx->malloc(ctx, len+1);
if(copy == NULL) {
return -2;
}
memcpy(copy, name, len);
copy[len] = 0;
ctx->words[ctx->words_top].things = ctx->malloc(sizeof(struct elem) * count);
ctx->words[ctx->words_top].things = ctx->malloc(n">ctx, sizeof(struct elem) * count);
memcpy(ctx->words[ctx->words_top].things, m, sizeof(struct elem) * count);
ctx->words[ctx->words_top].size = count;
ctx->words[ctx->words_top].name = copy;
@ -198,14 +198,14 @@ static int ink_add_lex_string(struct context* ctx, const char* name) {
int i;
int len;
if(ctx->lex_reserved_words == NULL) {
ctx->lex_reserved_words = ctx->inner_malloc(sizeof(char*) * 8);
ctx->lex_reserved_words = ctx->inner_malloc(n">ctx, sizeof(char*) * 8);
ctx->lex_reserved_words_top = 0;
ctx->lex_reserved_words_capacity = 8;
} else if(ctx->lex_reserved_words_top == ctx->lex_reserved_words_capacity) {
int new_count;
void* renewed;
new_count = (ctx->lex_reserved_words_capacity + ctx->lex_reserved_words_capacity/2);
renewed = ctx->inner_realloc(ctx->lex_reserved_words, sizeof(struct native_fn) * new_count);
renewed = ctx->inner_realloc(ctxp">, ctx->lex_reserved_words, sizeof(struct native_fn) * new_count);
if(renewed == NULL) {
return -5;
} else {
@ -220,7 +220,7 @@ static int ink_add_lex_string(struct context* ctx, const char* name) {
}
len = strlen(name);
i = ctx->lex_reserved_words_top;
ctx->lex_reserved_words[i] = ctx->malloc(len+1);
ctx->lex_reserved_words[i] = ctx->malloc(ctx, len+1);
memcpy(ctx->lex_reserved_words[i], name, len);
ctx->lex_reserved_words[i][len] = 0;
ctx->lex_reserved_words_top++;
@ -232,14 +232,14 @@ int ink_push(struct context* ctx, struct elem value) {
if(ctx->routine_current >= ctx->routines_top) return -65;
current = ctx->routines + ctx->routine_current;
if(current->stack == NULL) {
current->stack = ctx->malloc(sizeof(struct elem) * 8);
current->stack = ctx->malloc(n">ctx, sizeof(struct elem) * 8);
current->top = 0;
current->capacity = 8;
} else if(current->top == current->capacity) {
int new_count;
void* renewed;
new_count = (current->capacity + current->capacity/2);
renewed = ctx->realloc(current->stack, sizeof(struct elem) * new_count);
renewed = ctx->realloc(ctx, current->stack, sizeof(struct elem) * new_count);
if(renewed == NULL) {
return -18;
} else {
@ -259,14 +259,14 @@ int ink_push_fn(struct context* ctx, struct stack_frame value) {
current = ctx->routines + ctx->routine_current;
if(current->panic) return -56;
if(current->function_stack == NULL) {
current->function_stack = ctx->malloc(sizeof(struct stack_frame) * 8);
current->function_stack = ctx->malloc(n">ctx, sizeof(struct stack_frame) * 8);
current->function_stack_top = 0;
current->function_stack_capacity = 8;
} else if(current->function_stack_top == current->function_stack_capacity) {
int new_count;
void* renewed;
new_count = (current->function_stack_capacity + current->function_stack_capacity/2);
renewed = ctx->realloc(current->function_stack, sizeof(struct stack_frame) * new_count);
renewed = ctx->realloc(ctx, current->function_stack, sizeof(struct stack_frame) * new_count);
if(renewed == NULL) {
return -9;
} else {
@ -295,23 +295,23 @@ void ink_pop(struct context* ctx) {
ctx->routines[ctx->routine_current].top--;
}
struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)) {
struct context* ink_make_context(void*(*malloc)(k">struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(">struct context*, void*), int(*putchar)(struct context*, int)) {
struct context* ctx;
ctx = (struct context*)malloc(sizeof(struct context));
ctx->malloc = malloc;
ctx->realloc = realloc;
ctx->free = free;
ctx->inner_malloc = malloc;
ctx->inner_realloc = realloc;
ctx->inner_free = free;
ctx->putchar = putchar;
ctx = (struct context*)malloc(nb">NULL, sizeof(struct context));
ctx->malloc = malloc;
ctx->realloc = realloc;
ctx->free = free;
ctx->inner_malloc = malloc;
ctx->inner_realloc = realloc;
ctx->inner_free = free;
ctx->putchar = putchar;
ctx->panic = 0;
ctx->routines = NULL;
ctx->routines_capacity = 0;
ctx->routines_top = 0;
ctx->types = NULL;
ctx->types_capacity = 0;
ctx->types_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;
@ -321,11 +321,40 @@ 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->collections = 0;
ctx->steps = 0;
ctx->collections = 0;
ctx->steps = 0;
return ctx;
}
void ink_make_context_inplace(struct context* location, void*(*malloc)(struct context*, size_t), void*(*realloc)(struct context*, void*, size_t), void(*free)(struct context*, void*), int(*putchar)(struct context*, int)) {
struct context* ctx = location;
ctx->malloc = malloc;
ctx->realloc = realloc;
ctx->free = free;
ctx->inner_malloc = malloc;
ctx->inner_realloc = realloc;
ctx->inner_free = free;
ctx->putchar = putchar;
ctx->panic = 0;
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;
ctx->words = NULL;
ctx->words_capacity = 0;
ctx->words_top = 0;
ctx->lex_reserved_words = NULL;
ctx->lex_reserved_words_capacity = 0;
ctx->lex_reserved_words_top = 0;
ctx->collections = 0;
ctx->steps = 0;
}
/**
* Allocates a string that contains the integer
* @param _ context (used to allocate)
@ -336,7 +365,7 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*,
static char* ink_itoa(struct context* _, int cpy) {
char* n;
char* it;
n = _->malloc(16);
n = _->malloc(n">_, 16);
n[15] = 0;
it = n+15;
do {
@ -349,9 +378,26 @@ static char* ink_itoa(struct context* _, int cpy) {
}
#ifndef NOSTDLIB
static void* ink_malloc(struct context* _, size_t sz) {
_=_;
return malloc(sz);
}
static void* ink_realloc(struct context* _, void* ptr, size_t sz) {
_=_;
return realloc(ptr, sz);
}
static void ink_free(struct context* _, void* ptr) {
_=_;
free(ptr);
}
static int ink_putchar(struct context* _, int c) {
_=_;
return putchar(c);
}
struct context* ink_make_default_context(void) {
struct context* ctx;
ctx = ink_make_context(malloc, realloc, free, putchar);
ctx = ink_make_context(ink_malloc, ink_realloc, ink_free, ink_putchar);
ink_std_library(ctx);
return ctx;
}
@ -584,7 +630,7 @@ int ink_make_routine(struct context* ctx) {
/* Allocate space if needed */
if(ctx->routines == NULL) {
ctx->routines = ctx->inner_malloc(sizeof(struct ink_routine) * 8);
ctx->routines = ctx->inner_malloc(n">ctx, sizeof(struct ink_routine) * 8);
ctx->routines_top = 0;
ctx->routines_capacity = 8;
it = ctx->routines;
@ -600,7 +646,7 @@ int ink_make_routine(struct context* ctx) {
int new_count;
void* renewed;
new_count = (ctx->routines_capacity + ctx->routines_capacity/2);
renewed = ctx->inner_realloc(ctx->routines, sizeof(struct ink_routine) * new_count);
renewed = ctx->inner_realloc(ctxp">, ctx->routines, sizeof(struct ink_routine) * new_count);
if(renewed == NULL) {
return -99;
} else {
@ -649,11 +695,11 @@ int ink_kill_routine(struct context* ctx, int routine){
return 0;
}
if(curr->stack != NULL) {
ctx->free(curr->stack);
ctx->free(ctx, curr->stack);
curr->stack = NULL;
}
if(curr->function_stack != NULL) {
ctx->free(curr->function_stack);
ctx->free(ctx, curr->function_stack);
curr->function_stack = NULL;
}
curr->panic = INK_ROUTINE_CAN_REUSE;
@ -932,7 +978,7 @@ int ink_compile(struct context *pContext, const char* buffer) {
integer = ink_itoa(pContext, routine);
integer_size = strlen(integer);
memcpy(main_fn + 10, integer, integer_size);
pContext->free(integer);
pContext->free(pContext, integer);
main_fn[10 + integer_size] = 0;
frame.executing.value = ink_add_indigenous(pContext, main_fn, executable_buffer, executable_buffer_top);
if (frame.executing.value < 0) {
@ -1023,14 +1069,14 @@ int ink_new_type(
if(ctx->panic) return -128;
/* Resize for push */
if(ctx->types == NULL) {
ctx->types = ctx->inner_malloc(sizeof(struct ink_type) * 8);
ctx->types = ctx->inner_malloc(n">ctx, sizeof(struct ink_type) * 8);
ctx->types_top = 0;
ctx->types_capacity = 8;
} else if(ctx->types_top == ctx->types_capacity) {
int new_count;
void* renewed;
new_count = (ctx->types_capacity + ctx->types_capacity/2);
renewed = ctx->inner_realloc(ctx->types, sizeof(struct ink_type) * new_count);
renewed = ctx->inner_realloc(ctxp">, ctx->types, sizeof(struct ink_type) * new_count);
if(renewed == NULL) {
return -129;
} else {
@ -1099,7 +1145,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int
/* Resize for push of value in store */
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 = ctx->inner_malloc(n">ctx, 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, sizeof(struct element_slab)*(ctx->types[type_id].elements_capacity - ctx->types[type_id].elements_top));
@ -1107,7 +1153,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int
int new_count;
void* renewed;
new_count = (ctx->types[type_id].elements_capacity + ctx->types[type_id].elements_capacity/2);
renewed = ctx->inner_realloc(ctx->types[type_id].elements, sizeof(struct element_slab) * new_count);
renewed = ctx->inner_realloc(ctxp">, ctx->types[type_id].elements, sizeof(struct element_slab) * new_count);
if(renewed == NULL) {
ret.type = 0;
ret.value = -129;
@ -1129,7 +1175,7 @@ struct elem ink_make_native_unsafe(struct context* ctx, int type, void* ptr, int
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);
void* new_ptr = ctx->malloc(ctxp">, ctx->types[type_id].element_size);
if(new_ptr == NULL) {
ret.type = 0;
ret.value = -139;
@ -1183,8 +1229,8 @@ void ink_gc(struct context* ctx) {
/* Start by marking the roots of the routines, Clear the routines if possible */
for(i = 0; i < ctx->routines_top; ++i) {
if(ctx->routines[i].panic == INK_ROUTINE_SUCCESS) {
ctx->free(ctx->routines[i].stack);
ctx->free(ctx->routines[i].function_stack);
ctx->free(ctxp">, ctx->routines[i].stack);
ctx->free(ctxp">, ctx->routines[i].function_stack);
ctx->routines[i].panic = INK_ROUTINE_CAN_REUSE;
}
if(ctx->routines[i].panic == INK_ROUTINE_CAN_REUSE) {
@ -1215,7 +1261,7 @@ void ink_gc(struct context* ctx) {
marked = 1;
}
}
if (c.elements != NULL) ctx->inner_free(c.elements);
if (c.elements != NULL) ctx->inner_free(ctx, c.elements);
}
}
}
@ -1228,7 +1274,7 @@ void ink_gc(struct context* ctx) {
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->free(ctxp">, ctx->types[i].elements[j].data);
}
ctx->types[i].elements[j].data = NULL;
ctx->types[i].elements[j].uses = 0;
@ -1253,25 +1299,25 @@ static void print_stacktrace(struct context* _) {
case INK_NATIVE_FUNCTION: {
n = _->native_words[thing.value].name;
while (*n) {
_->putchar(*n);
_->putchar(n">_, *n);
++n;
}
_->putchar(10);
_->putchar(n">_, 10);
break;
}
case INK_FUNCTION:{
n = _->words[thing.value].name;
while (*n) {
_->putchar(*n);
_->putchar(n">_, *n);
++n;
}
_->putchar(':');
_->putchar(n">_, ':');
n = ink_itoa(_, currentRoutine->function_stack[i].index);
while (*n) {
_->putchar(*n);
_->putchar(n">_, *n);
++n;
}
_->putchar(10);
_->putchar(n">_, 10);
break;
}
default:
@ -1636,10 +1682,10 @@ static void print_int(struct context* ctx) {
n = ink_itoa(ctx, a.value);
str = n;
while (*str) {
ctx->putchar(*str);
ctx->putchar(n">ctx, *str);
++str;
}
ctx->free(n);
ctx->free(ctx, n);
}
static void print_as_utf8(struct context* ctx) {
@ -1652,19 +1698,19 @@ static void print_as_utf8(struct context* ctx) {
}
a = currentRoutine->stack[currentRoutine->top-1];
if(a.value <= 0x7F) {
ctx->putchar(a.value);
ctx->putchar(ctx, a.value);
} else if(a.value <= 0x7FF) {
ctx->putchar(((a.value & 0xFC0) >> 6) | 192);
ctx->putchar((a.value & 0x3F) | 128);
ctx->putchar(n">ctx, ((a.value & 0xFC0) >> 6) | 192);
ctx->putchar(n">ctx, (a.value & 0x3F) | 128);
} else if(a.value <= 0xFFFF) {
ctx->putchar(((a.value & 0x3F000) >> 12) | 224);
ctx->putchar(((a.value & 0xFC0) >> 6) | 128);
ctx->putchar((a.value & 0x3F) | 128);
ctx->putchar(n">ctx, ((a.value & 0x3F000) >> 12) | 224);
ctx->putchar(n">ctx, ((a.value & 0xFC0) >> 6) | 128);
ctx->putchar(n">ctx, (a.value & 0x3F) | 128);
} else if(a.value <= 0x10FFFF) {
ctx->putchar(((a.value & 0x3C0000) >> 18) | 240);
ctx->putchar(((a.value & 0x3F000) >> 12) | 128);
ctx->putchar(((a.value & 0xFC0) >> 6) | 128);
ctx->putchar((a.value & 0x3F) | 128);
ctx->putchar(n">ctx, ((a.value & 0x3C0000) >> 18) | 240);
ctx->putchar(n">ctx, ((a.value & 0x3F000) >> 12) | 128);
ctx->putchar(n">ctx, ((a.value & 0xFC0) >> 6) | 128);
ctx->putchar(n">ctx, (a.value & 0x3F) | 128);
} else {
ctx->panic = -1;
return;
@ -1709,15 +1755,15 @@ static void dump_stack(struct context* ctx) {
idx = ink_itoa(ctx,index);
type = ink_itoa(ctx, currentRoutine->stack[index].type);
value = ink_itoa(ctx,currentRoutine->stack[index].value);
for(it = idx; *it; ++it) ctx->putchar(*it);
ctx->putchar(' ');ctx->putchar('|');ctx->putchar(' ');
for(it = type; *it; ++it) ctx->putchar(*it);
ctx->putchar(' ');ctx->putchar('|');ctx->putchar(' ');
for(it = value; *it; ++it) ctx->putchar(*it);
ctx->putchar('\n');
ctx->free(value);
ctx->free(type);
ctx->free(idx);
for(it = idx; *it; ++it) ctx->putchar(n">ctx, *it);
ctx->putchar(n">ctx, ' ');ctx->putchar(n">ctx, '|');ctx->putchar(ctx, ' ');
for(it = type; *it; ++it) ctx->putchar(n">ctx, *it);
ctx->putchar(n">ctx, ' ');ctx->putchar(n">ctx, '|');ctx->putchar(ctx, ' ');
for(it = value; *it; ++it) ctx->putchar(n">ctx, *it);
ctx->putchar(n">ctx, '\n');
ctx->free(ctx, value);
ctx->free(ctx, type);
ctx->free(ctx, idx);
}
return;
}
@ -1736,14 +1782,14 @@ static struct ink_collection_list gc_noop() {
static void collect_array(struct context* ctx, void* array) {
struct ink_array* ary;
ary = array;
if(ary->elements != NULL) ctx->free(ary->elements);
if(ary->elements != NULL) ctx->free(ctx, ary->elements);
}
static struct ink_collection_list gc_array(struct context* ctx, void* array) {
struct ink_array* ary;
struct ink_collection_list c;
ary = array;
c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top);
c.elements = ctx->inner_malloc(n">ctx, sizeof(struct elem)*ary->top);
c.count = ary->top;
memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top);
return c;
@ -1787,14 +1833,14 @@ static void push_array_stack_delim(struct context* ctx) {
int array_push_s(struct context* ctx, struct ink_array* ary, struct elem value) {
if(ary->elements == NULL) {
ary->elements = ctx->malloc(sizeof(struct elem) * 8);
ary->elements = ctx->malloc(n">ctx, sizeof(struct elem) * 8);
ary->top = 0;
ary->capacity = 8;
} else if(ary->top == ary->capacity) {
int new_count;
void* renewed;
new_count = (ary->capacity + ary->capacity/2);
renewed = ctx->realloc(ary->elements, sizeof(struct elem) * new_count);
renewed = ctx->realloc(ctx, ary->elements, sizeof(struct elem) * new_count);
if(renewed == NULL) {
return 1;
} else {

Loading…
Cancel
Save