|
|
- #include "ink.h"
- #ifndef NOSTDLIB
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #ifdef INSTRUMENTATION
- #include <time.h>
- #endif
- #endif
-
- #define INK_RESERVED (-1)
- #define INK_FUNCTION_KW (-2)
- #define INK_DO_KW (-3)
- #define INK_END_KW (-4)
- #define INK_LABEL (-5)
- #define INK_RETURN (-6)
-
- #define _KEYWORD_INK_FUNCTION "fn"
- #define _KEYWORD_INK_DO "do"
- #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;
- char* name;
- };
-
- #ifdef NOSTDLIB
-
- static size_t strlen(const char* c) {
- size_t j = 0;
- while(*(c++)) {
- j++;
- }
- return j;
- }
-
- static void* memcpy(void* _dest, const void* _src, size_t sz) {
- char* dest = _dest;
- const char* src = _src;
- while(sz--) {
- *(dest++) = *(src++);
- }
- return dest;
- }
-
- static int strcmp(const char* dest, const char* src) {
- while(*dest != 0 && *src != 0) {
- if(*(dest++) != *(src++)) {
- return 1;
- }
- }
- return 0;
- }
-
- static void* memmove(void* _dest, const void* _src, size_t sz) {
- char* dest = _dest;
- const char* src = _src;
- if (src < dest) {
- src += sz;
- dest += sz;
- while (sz-- > 0) {
- *--dest = *--src;
- }
- } else {
- while (sz-- > 0) {
- *dest++ = *src++;
- }
- }
- return dest;
- }
-
- static void* memset(void* _dest, int src, size_t sz) {
- char* dest = _dest;
- while(sz--) {
- *(dest++) = src++;
- }
- return dest;
- }
-
- static int isspace(int d) {
- return d == ' ' || d == '\t' || d == '\n';
- }
-
- static int isdigit(int d) {
- return '0' <= d && d <= '9';
- }
-
- static int atoi(const char* c) {
- int ret = 0;
- while(*c) {
- ret *= 10;
- ret += *c - '0';
- ++c;
- }
- return ret;
- }
-
- #endif
-
- int ink_add_native(struct context* ctx, const char* name, void(*value)(struct context*)) {
- if(ctx->native_words == NULL) {
- ctx->native_words = ctx->inner_malloc(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 = (ctx->native_words_capacity + ctx->native_words_capacity/2);
- void* renewed = ctx->inner_realloc(ctx->native_words, sizeof(struct native_fn) * new_count);
- if(renewed == NULL) {
- return -3;
- } else {
- ctx->native_words = renewed;
- ctx->native_words_capacity = new_count;
- }
- }
- int len = strlen(name);
- char* copy = ctx->inner_malloc(len+1);
- if(copy == NULL) {
- return -4;
- }
- memcpy(copy, name, len);
- copy[len] = 0;
- ctx->native_words[ctx->native_words_top].value = value;
- ctx->native_words[ctx->native_words_top].name = copy;
- ctx->native_words_top++;
- return 0;
- }
-
- static int ink_add_indigenous(struct context* ctx, const char* name, struct elem* m, size_t count) {
- if(ctx->words == NULL) {
- ctx->words = ctx->malloc(sizeof(struct fn) * 8);
- ctx->words_top = 0;
- ctx->words_capacity = 8;
- } else if(ctx->words_top == ctx->words_capacity) {
- int new_count = (ctx->words_capacity + ctx->words_capacity/2);
- void* renewed = ctx->realloc(ctx->words, sizeof(struct native_fn) * new_count);
- if(renewed == NULL) {
- return -1;
- } else {
- ctx->words = renewed;
- ctx->words_capacity = new_count;
- }
- }
- int i;
- 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);
- memcpy(ctx->words[i].things, m, sizeof(struct elem) * count);
- ctx->words[i].size = count;
- return i;
- }
- }
- int len = strlen(name);
- char* copy = ctx->malloc(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);
- 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;
- return ctx->words_top++;
- }
-
- static int ink_add_lex_string(struct context* ctx, const char* name) {
- int i;
- if(ctx->lex_reserved_words == NULL) {
- ctx->lex_reserved_words = ctx->inner_malloc(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 = (ctx->lex_reserved_words_capacity + ctx->lex_reserved_words_capacity/2);
- void* renewed = ctx->inner_realloc(ctx->lex_reserved_words, sizeof(struct native_fn) * new_count);
- if(renewed == NULL) {
- return -5;
- } else {
- ctx->lex_reserved_words = renewed;
- ctx->lex_reserved_words_capacity = new_count;
- }
- }
- for(i = 0; i < ctx->lex_reserved_words_top; i++) {
- if(strcmp(ctx->lex_reserved_words[i], name) == 0) {
- return i;
- }
- }
- int len = strlen(name);
- i = ctx->lex_reserved_words_top;
- ctx->lex_reserved_words[i] = ctx->malloc(len+1);
- memcpy(ctx->lex_reserved_words[i], name, len);
- ctx->lex_reserved_words[i][len] = 0;
- ctx->lex_reserved_words_top++;
- return i;
- }
-
- int ink_push(struct context* ctx, struct elem value) {
- if(ctx->routine_current >= ctx->routines_top) return -65;
- struct ink_routine* current = ctx->routines + ctx->routine_current;
- if(current->stack == NULL) {
- current->stack = ctx->malloc(sizeof(struct elem) * 8);
- current->top = 0;
- current->capacity = 8;
- } else if(current->top == current->capacity) {
- int new_count = (current->capacity + current->capacity/2);
- void* renewed = ctx->realloc(current->stack, sizeof(struct elem) * new_count);
- if(renewed == NULL) {
- return -18;
- } else {
- current->stack = renewed;
- current->capacity = new_count;
- }
- }
- current->stack[current->top] = value;
- current->top++;
- return 0;
- }
-
- int ink_push_fn(struct context* ctx, struct stack_frame value) {
- if(ctx->routine_current >= ctx->routines_top) return -55;
- struct ink_routine* 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_top = 0;
- current->function_stack_capacity = 8;
- } else if(current->function_stack_top == current->function_stack_capacity) {
- int new_count = (current->function_stack_capacity + current->function_stack_capacity/2);
- void* renewed = ctx->realloc(current->function_stack, sizeof(struct stack_frame) * new_count);
- if(renewed == NULL) {
- return -9;
- } else {
- current->function_stack = renewed;
- current->function_stack_capacity = new_count;
- }
- }
- current->function_stack[current->function_stack_top] = value;
- current->function_stack_top++;
- return 0;
- }
-
- void ink_pop_fn(struct context* ctx) {
- if(ctx->routine_current >= ctx->routines_top) return;
- if(ctx->routines[ctx->routine_current].panic) return;
- if(ctx->routines[ctx->routine_current].function_stack == NULL) return;
- if(ctx->routines[ctx->routine_current].function_stack_top == 0) return;
- ctx->routines[ctx->routine_current].function_stack_top--;
- }
-
- void ink_pop(struct context* ctx) {
- if(ctx->routine_current >= ctx->routines_top) return;
- if(ctx->routines[ctx->routine_current].panic) return;
- if(ctx->routines[ctx->routine_current].stack == NULL) return;
- if(ctx->routines[ctx->routine_current].top == 0) return;
- 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* 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->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;
- return ctx;
- }
-
- /**
- * Allocates a string that contains the integer
- * @param _ context (used to allocate)
- * @param cpy the value
- * @return the allocated string, needs to be freed by ctx->free
- * @internal this function is slightly cursed
- */
- static char* ink_itoa(struct context* _, int cpy) {
- char* n = _->malloc(16);
- n[15] = 0;
- char* it = n+15;
- do {
- it--;
- *it = (cpy % 10) + '0';
- cpy = cpy / 10;
- } while(cpy);
- memmove(n, it, 16 - (it-n));
- return n;
- }
-
- #ifndef NOSTDLIB
- struct context* ink_make_default_context() {
- struct context* ctx = ink_make_context(malloc, realloc, free, putchar);
- ink_std_library(ctx);
- return ctx;
- }
- #endif
-
- static int ink_consume_one(int* end, struct context* pContext, char** buffer, char* r) {
- int i;
- if(*end == 0) {
- return 0;
- }
- r[*end] = 0;
- int done = 0;
- struct elem value;
- if (strcmp(r, _KEYWORD_INK_FUNCTION) == 0) {
- value.value = 0;
- value.type = INK_FUNCTION_KW;
- done = 1;
- }
- if (!done && strcmp(r, _KEYWORD_INK_DO) == 0) {
- value.value = 0;
- value.type = INK_DO_KW;
- done = 1;
- }
- if (!done && strcmp(r, _KEYWORD_INK_END) == 0) {
- value.value = 0;
- value.type = INK_END_KW;
- done = 1;
- }
- if (!done && strcmp(r, _KEYWORD_INK_RETURN) == 0) {
- value.value = 0;
- value.type = INK_RETURN;
- done = 1;
- }
- if(done) {
- int err;
- err = ink_push(pContext, value);
- if(err < 0) {
- return -19;
- }
- }
- if (!done) {
- for (i = 0; i < pContext->words_top; ++i) {
- if (strcmp(r, pContext->words[i].name) == 0) {
- value.value = i;
- value.type = INK_FUNCTION;
- int err;
- err = ink_push(pContext, value);
- if(err < 0) {
- return -20;
- }
- done = 1;
- break;
- }
- }
- }
- if (!done) {
- for (i = 0; i < pContext->native_words_top; ++i) {
- if (strcmp(r, pContext->native_words[i].name) == 0) {
- value.value = i;
- value.type = INK_NATIVE_FUNCTION;
- int err;
- err = ink_push(pContext, value);
- if(err < 0) {
- return -21;
- }
- done = 1;
- break;
- }
- }
- }
- if (!done) {
- for(i = (r[0] == '-'); i < *end; i++) {
- if(!isdigit(r[i])){
- goto not_an_int;
- }
- }
- value.value = atoi(r);
- value.type = INK_INTEGER;
- int err;
- err = ink_push(pContext, value);
- if(err < 0) {
- return -22;
- }
- done = 1;
- }
- not_an_int:
- if (!done) {
- i = ink_add_lex_string(pContext, r);
- if(i < 0) {
- pContext->panic = 1;
- return -7;
- }
- value.value = i;
- if(r[strlen(r) - 1] == ':') {
- value.type = INK_LABEL;
- } else {
- value.type = INK_RESERVED;
- }
- int err;
- err = ink_push(pContext, value);
- if(err < 0) {
- return -23;
- }
- }
- *end = 0;
- return 0;
- }
-
- static int ink_lex(struct context *pContext, char* buffer) {
- int i;
- char r[128];
- int end = 0;
- int err;
-
- while(*buffer != 0) {
- if(isspace(*buffer)) {
- err = ink_consume_one(&end, pContext, &buffer, r);
- if(err < 0) {
- pContext->panic = 1;
- return -8;
- }
- } else {
- r[end] = *buffer;
- ++end;
- }
- ++buffer;
- }
- err = ink_consume_one(&end, pContext, &buffer, r);
- if(err < 0) {
- pContext->panic = 1;
- return -9;
- }
- return 0;
- }
-
- static int lblcmp(const char* label, const char* other, size_t label_sz) {
- while (label_sz != 1) {
- if(*other == 0) return 1;
- if(*label != *other) return 1;
- ++label;
- ++other;
- label_sz--;
- }
- return 0;
- }
-
- int ink_make_routine(struct context* ctx) {
- if(ctx->routines == NULL) {
- ctx->routines = ctx->inner_malloc(sizeof(struct ink_routine) * 8);
- ctx->routines_top = 0;
- ctx->routines_capacity = 8;
- struct ink_routine* it = ctx->routines;
- struct ink_routine* end = ctx->routines + 8;
- for(;it != end;++it) {
- it->stack = NULL;
- it->function_stack = NULL;
- it->panic = INK_ROUTINE_CAN_REUSE;
- }
- } else if(ctx->routines_top == ctx->routines_capacity) {
- int new_count = (ctx->routines_capacity + ctx->routines_capacity/2);
- void* renewed = ctx->inner_realloc(ctx->routines, sizeof(struct stack_frame) * new_count);
- if(renewed == NULL) {
- return -99;
- } else {
- ctx->routines = renewed;
- struct ink_routine* it = ctx->routines + ctx->routines_capacity;
- struct ink_routine* end = ctx->routines + new_count;
- for(;it != end;++it) {
- it->panic = INK_ROUTINE_CAN_REUSE;
- }
- ctx->routines_capacity = new_count;
- }
- }
-
- struct ink_routine* it = ctx->routines;
- struct ink_routine* end = ctx->routines + ctx->routines_capacity;
-
- for(;it != end;++it) {
- if(it->panic == INK_ROUTINE_CAN_REUSE) {
- it->panic = 0;
- it->stack = NULL;
- it->top = 0;
- it->capacity = 0;
- it->function_stack = NULL;
- it->function_stack_top = 0;
- it->function_stack_capacity = 0;
- int idx = it - ctx->routines;
- if(idx >= ctx->routines_top) {
- ctx->routines_top = idx + 1;
- }
- return idx;
- }
- }
- }
-
- int ink_kill_routine(struct context* ctx, int routine){
- if(routine < 0 || routine >= ctx->routines_top) {
- return 0;
- }
- struct ink_routine* curr = ctx->routines + routine;
- if(curr->panic == INK_ROUTINE_CAN_REUSE) {
- return 0;
- }
- if(curr->stack != NULL) {
- ctx->free(curr->stack);
- curr->stack = NULL;
- }
- if(curr->function_stack != NULL) {
- ctx->free(curr->function_stack);
- curr->function_stack = NULL;
- }
- curr->panic = INK_ROUTINE_CAN_REUSE;
- return 1;
- }
-
- /**
- *
- * @param pContext
- * @param executable_buffer
- * @param executable_buffer_top
- * @internal Loop from hell
- */
- static int ink_parse(struct context* pContext, struct elem* executable_buffer, int* executable_buffer_top) {
- struct ink_routine* currentRoutine = pContext->routines + pContext->routine_current;
- int i;
- #define LABEL_BUFFER 128
- #define FUNCTION_BUFFER 256
- struct label labels[LABEL_BUFFER];
- struct elem function_buffer[FUNCTION_BUFFER];
- int function_buffer_top = 0;
- int function_name = -1;
- #define MODE_EXECUTABLE 0
- #define MODE_FUNCTION 1
- #define MODE_DO 2
- int mode = 0;
- memset(labels, 0, sizeof(struct label)*LABEL_BUFFER);
- for(i = 0; i < currentRoutine->top; ++i) {
- struct elem current;
- current = currentRoutine->stack[i];
- switch (mode) {
- case MODE_EXECUTABLE:
- switch(current.type) {
- case INK_FUNCTION_KW:
- mode = MODE_FUNCTION;
- function_name = -1;
- goto next_token;
- case INK_DO_KW:
- case INK_END_KW:
- return -26;
- default:
- executable_buffer[*executable_buffer_top] = current;
- *executable_buffer_top += 1;
- }
- break;
- case MODE_FUNCTION:
- if(current.type == INK_DO_KW) {
- if(function_name == -1) {
- return -27;
- } else {
- mode = MODE_DO;
- memset(labels, 0, sizeof(struct label)*128);
- goto next_token;
- }
- }
- if(function_name != -1) {
- return -28;
- }
- if(current.type != INK_RESERVED) {
- return -29;
- }
- function_name = current.value;
- break;
- case MODE_DO:
- if(current.type == INK_END_KW) {
- int j;
- for(j = 0; j < function_buffer_top; j++) {
- struct elem pt;
- pt = function_buffer[j];
- if(pt.type == INK_LABEL) {
- int k;
- for(k = 0; k < LABEL_BUFFER; k++) {
- if(labels[k].active) {
- if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) {
- labels[k].dest = j;
- return -30;
- break;
- }
- } else {
- labels[k].active = 1;
- labels[k].name = pContext->lex_reserved_words[pt.value];
- labels[k].dest = j;
- memcpy(function_buffer+j, function_buffer+j+1, sizeof(struct elem)*(function_buffer_top-j-1));
- function_buffer_top--;
- j--;
- break;
- }
- }
- }
- }
- for(j = 0; j < function_buffer_top; j++) {
- struct elem pt;
- pt = function_buffer[j];
- if(pt.type == INK_RESERVED) {
- const char* str = pContext->lex_reserved_words[pt.value];
- int k;
- for(k = 0; k < LABEL_BUFFER; k++) {
- if(labels[k].active) {
- const char* lbl = labels[k].name;
- int label_sz = strlen(lbl);
- if(lblcmp(labels[k].name, pContext->lex_reserved_words[pt.value], label_sz) == 0) {
- function_buffer[j].type = INK_INTEGER;
- function_buffer[j].value = labels[k].dest - j;
- break;
- }
- } else break;
- }
- }
- }
- int err;
- err = ink_add_indigenous(pContext, pContext->lex_reserved_words[function_name], function_buffer, function_buffer_top);
- if(err < 0) {
- pContext->panic = 1;
- return -33;
- }
- function_buffer_top = 0;
- mode = MODE_EXECUTABLE;
- goto next_token;
- }
- function_buffer[function_buffer_top] = current;
- function_buffer_top += 1;
- break;
- }
- next_token: i=i;
- }
- if(mode == MODE_FUNCTION || mode == MODE_DO) {
- return -32;
- }
- return 0;
- #undef MODE_EXECUTABLE
- #undef MODE_FUNCTION
- #undef MODE_DO
-
- #undef LABEL_BUFFER
- #undef FUNCTION_BUFFER
- }
-
- int ink_step(struct context *pContext) {
- struct ink_routine* currentRoutine = pContext->routines + pContext->routine_current;
- pContext->steps++;
- if(currentRoutine->function_stack_top == 0) return 0;
- if(pContext->panic) {
- return -1;
- }
- struct stack_frame frame;
- struct stack_frame* top;
- struct elem next;
- int t;
- top = ¤tRoutine->function_stack[currentRoutine->function_stack_top-1];
- t = top->executing.type;
- switch(t) {
- case INK_NATIVE_FUNCTION:
- if(top->index != 0) {
- ink_pop_fn(pContext);
- } else {
- top->index++;
- if(pContext->native_words_top <= top->executing.value) {
- pContext->panic = 1;
- return -1;
- }
- pContext->native_words[top->executing.value].value(pContext);
- }
- break;
- case INK_FUNCTION:
- if(pContext->words_top <= top->executing.value) {
- pContext->panic = 1;
- return -1;
- }
- if(top->index >= pContext->words[top->executing.value].size) {
- ink_pop_fn(pContext);
- } else {
- next = pContext->words[top->executing.value].things[top->index];
- if(next.type == INK_RETURN) {
- ink_pop_fn(pContext);
- return 1;
- }
- frame.executing = next;
- frame.index = 0;
- t = ink_push_fn(pContext, frame);
- if(t < 0) {
- pContext->panic = 1;
- return -11;
- }
- top->index++;
- }
- break;
- default:
- t = ink_push(pContext, top->executing);
- if(t < 0) {
- pContext->panic = 1;
- return -25;
- }
- ink_pop_fn(pContext);
- break;
- }
- return 1;
- }
-
- void ink_compile(struct context *pContext, char* buffer) {
- int routine = ink_make_routine(pContext);
- int saved = pContext->routine_current;
- pContext->routine_current = routine;
- struct ink_routine* currentRoutine = pContext->routines + routine;
- currentRoutine->stack = NULL;
- currentRoutine->top = 0;
- currentRoutine->capacity = 0;
- int err;
- err = ink_lex(pContext, buffer);
- if(err < 0) {
- pContext->panic = 1;
- return;
- }
- int i = 0;
- struct elem executable_buffer[256];
- int executable_buffer_top = 0;
- err = ink_parse(pContext, executable_buffer, &executable_buffer_top);
- if(err < 0) {
- pContext->panic = 1;
- return;
- }
- struct stack_frame frame;
- char main_fn[32] = "__-MAIN-__";
- char* integer = ink_itoa(pContext, routine);
- size_t integer_size = strlen(integer);
- memcpy(main_fn+10, integer, integer_size);
- pContext->free(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) {
- pContext->panic = 1;
- return;
- }
- frame.executing.type = INK_FUNCTION;
- frame.index = 0;
- err = ink_push_fn(pContext, frame);
- if(err < 0) {
- pContext->panic = 1;
- return;
- }
-
- pContext->routine_current = saved;
- return;
- }
-
- int ink_can_run(struct context* pContext) {
- int it = 0;
- for(;it < pContext->routines_top; ++it) {
- if(pContext->routines[it].panic == 0) {
- return 1;
- }
- }
- return 0;
- }
-
- int ink_step_everyone(struct context* pContext) {
- int out;
- pContext->routine_current = -1;
- for(;;) {
- do{
- ++(pContext->routine_current);
- } while(pContext->routine_current < pContext->routines_top && pContext->routines[pContext->routine_current].panic != 0);
- if(pContext->routine_current >= pContext->routines_top) break;
- if(pContext->routines[pContext->routine_current].panic == INK_ROUTINE_SUCCESS) {
- ink_kill_routine(pContext, pContext->routine_current);
- }
- out = ink_step(pContext);
- if(out == 0) {
- pContext->routines[pContext->routine_current].panic = INK_ROUTINE_SUCCESS;
- } else if(out < 0) {
- pContext->routines[pContext->routine_current].panic = out;
- }
- }
- 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* _) {
- int i = 0;
- struct ink_routine* currentRoutine = _->routines + _->routine_current;
- for(; i < currentRoutine->function_stack_top; ++i) {
- struct elem thing;
- thing = currentRoutine->function_stack[i].executing;
- switch(thing.type) {
- case INK_NATIVE_FUNCTION: {
- char *n = _->native_words[thing.value].name;
- while (*n) {
- _->putchar(*n);
- ++n;
- }
- _->putchar(10);
- break;
- }
- case INK_FUNCTION:{
- char *n = _->native_words[thing.value].name;
- while (*n) {
- _->putchar(*n);
- ++n;
- }
- _->putchar(':');
- n = ink_itoa(_, currentRoutine->function_stack[i].index);
- while (*n) {
- _->putchar(*n);
- ++n;
- }
- _->free(n);
- _->putchar(10);
- break;
- }
- default:
- break;
- }
- }
- }
-
- static void add_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
- ctx->panic = 1;
- return;
- }
- ink_pop(ctx);
- currentRoutine->stack[currentRoutine->top-1].value = a.value + b.value;
- }
-
- static void sub_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
- currentRoutine->panic = 1;
- return;
- }
- ink_pop(ctx);
- currentRoutine->stack[currentRoutine->top-1].value = b.value - a.value;
- }
-
- static void mult_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
- currentRoutine->panic = 1;
- return;
- }
- ink_pop(ctx);
- currentRoutine->stack[currentRoutine->top-1].value = b.value * a.value;
- }
-
- static void div_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
- currentRoutine->panic = 1;
- return;
- }
- ink_pop(ctx);
- currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value;
- }
-
- static void rem_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
- currentRoutine->panic = 1;
- return;
- }
- ink_pop(ctx);
- currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value;
- }
-
- static void dupe_elem(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1) {
- ctx->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- int err;
- err = ink_push(ctx, a);
- if(err < 0) ctx->panic;
- }
-
- static void drop_elem(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1) {
- ctx->panic = 1;
- return;
- }
- ink_pop(ctx);
- }
-
- static void pluck_elem(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- if(a.type != INK_INTEGER) {
- ctx->panic = 1;
- return;
- }
- int position = currentRoutine->top - (a.value + 1);
- if(position >= currentRoutine->top || position < 0) {
- ctx->panic = 1;
- return;
- }
- ink_pop(ctx);
- int err;
- err = ink_push(ctx, currentRoutine->stack[position]);
- if(err < 0) ctx->panic;
- }
-
- static void swap_elem(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 2) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- struct elem b;
- a = currentRoutine->stack[currentRoutine->top-1];
- b = currentRoutine->stack[currentRoutine->top-2];
- currentRoutine->stack[currentRoutine->top-2] = a;
- currentRoutine->stack[currentRoutine->top-1] = b;
- }
-
- static void return_if(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1) {
- ctx->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- if(a.type != INK_INTEGER) {
- ctx->panic = 1;
- return;
- }
- if(a.value) {
- ink_pop_fn(ctx);
- ink_pop_fn(ctx);
- }
- ink_pop(ctx);
- return;
- }
-
- static void jump_if(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1) {
- ctx->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- if(a.type != INK_INTEGER) {
- ctx->panic = 1;
- return;
- }
- ink_pop(ctx);
- if(a.value) {
- ink_pop_fn(ctx);
- a = currentRoutine->stack[currentRoutine->top-1];
- currentRoutine->function_stack[currentRoutine->function_stack_top - 1].index += a.value - 3;
- }
- ink_pop(ctx);
- return;
- }
-
- static void print_int(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) {
- currentRoutine->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- ink_pop(ctx);
- char* n = ink_itoa(ctx, a.value);
- char* str = n;
- while (*str) {
- ctx->putchar(*str);
- ++str;
- }
- ctx->free(n);
- }
-
- static void print_as_utf8(struct context* ctx) {
- struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current;
- if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) {
- ctx->panic = 1;
- return;
- }
- struct elem a;
- a = currentRoutine->stack[currentRoutine->top-1];
- if(a.value <= 0x7F) {
- ctx->putchar(a.value);
- } else if(a.value <= 0x7FF) {
- ctx->putchar(((a.value & 0xFC0) >> 6) | 192);
- ctx->putchar((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);
- } 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);
- } else {
- ctx->panic = 1;
- return;
- }
- 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;
- 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);
- v += ink_add_native(ctx, "-", sub_int);
- v += ink_add_native(ctx, "*", mult_int);
- v += ink_add_native(ctx, "/", div_int);
- v += ink_add_native(ctx, "%", rem_int);
- v += ink_add_native(ctx, "swap", swap_elem);
- v += ink_add_native(ctx, "dup", dupe_elem);
- v += ink_add_native(ctx, "drop", drop_elem);
- v += ink_add_native(ctx, "pluck", pluck_elem);
- v += ink_add_native(ctx, "return_if", return_if);
- v += ink_add_native(ctx, "jump_if", jump_if);
- return v;
- }
|