|
|
|
@ -88,7 +88,7 @@ static int routine_assert(struct context* ctx, int condition, int error, const c |
|
|
|
* @param message a message that will be printed in the output, no need to add a new line at the end :) |
|
|
|
* @return true if the assertion failed, so as to allow for a `if(routine_assert(...)) return ...;` |
|
|
|
*/ |
|
|
|
static int context_assert(struct context* ctx, int condition, int error, const char* message) { |
|
|
|
static int context_assert(struct context* ctx, int condition, ">const int error, const char* message) { |
|
|
|
condition = !condition; |
|
|
|
if (condition) { |
|
|
|
ctx->panic = error; |
|
|
|
@ -102,6 +102,8 @@ static int context_assert(struct context* ctx, int condition, int error, const c |
|
|
|
|
|
|
|
#ifdef NOSTDLIB |
|
|
|
|
|
|
|
#define EOF ((int)(-1)) |
|
|
|
|
|
|
|
static size_t strlen(const char* c) { |
|
|
|
size_t j; |
|
|
|
j = 0; |
|
|
|
@ -178,13 +180,26 @@ static int atoi(const char* c) { |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int memcmp(const void *s1, const void *s2, size_t n) { |
|
|
|
if (n != 0) { |
|
|
|
const unsigned char *p1 = s1, *p2 = s2; |
|
|
|
|
|
|
|
do { |
|
|
|
if (*p1++ != *p2++) { |
|
|
|
return (*--p1 - *--p2); |
|
|
|
} |
|
|
|
} while (--n != 0); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
static int utf8_consume(const char ** name, struct elem * elem) { |
|
|
|
elem->type = INK_INTEGER; |
|
|
|
if (**name == '\0') { return 0; } |
|
|
|
if (!(**name & 128)) { |
|
|
|
elem->value = **name; |
|
|
|
elem->value = p">(unsigned char)**name; |
|
|
|
*name += 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
@ -265,10 +280,9 @@ int ink_add_native(struct context* ctx, const char* name, void(*value)(struct co |
|
|
|
renewed = ctx->inner_realloc(ctx, 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; |
|
|
|
} |
|
|
|
ctx->native_words = renewed; |
|
|
|
ctx->native_words_capacity = new_count; |
|
|
|
} |
|
|
|
name_it = name; |
|
|
|
while (utf8_consume(&name_it, &character)) { |
|
|
|
@ -346,10 +360,9 @@ static int ink_add_indigenous_already_array(struct context* ctx, struct elem e, |
|
|
|
renewed = ctx->realloc(ctx, ctx->words, sizeof(struct fn) * new_count); |
|
|
|
if(renewed == NULL) { |
|
|
|
return -1; |
|
|
|
} else { |
|
|
|
ctx->words = renewed; |
|
|
|
ctx->words_capacity = new_count; |
|
|
|
} |
|
|
|
ctx->words = renewed; |
|
|
|
ctx->words_capacity = new_count; |
|
|
|
} |
|
|
|
for(i = 0; i < ctx->words_top; ++i) { |
|
|
|
if(e.value == ctx->words[i].name.value) { |
|
|
|
@ -436,10 +449,10 @@ int ink_push(struct context* ctx, struct elem value) { |
|
|
|
|
|
|
|
int ink_push_fn(struct context* ctx, struct stack_frame value) { |
|
|
|
struct ink_routine* current; |
|
|
|
|
|
|
|
if(ctx->routine_current >= ctx->routines_top) return -55; |
|
|
|
if(context_assert(ctx, ctx->routine_current >= ctx->routines_top, -55, "Trying to run in a routine that does not exist (ink_push_fn)")) return -55; |
|
|
|
current = ctx->routines + ctx->routine_current; |
|
|
|
if(current->panic) return -56; |
|
|
|
|
|
|
|
if(context_assert(ctx, current->panic, -56, "Trying to run in a routine that is panicked (ink_push_fn)")) return -56; |
|
|
|
if(current->function_stack == NULL) { |
|
|
|
current->function_stack = ctx->malloc(ctx, sizeof(struct stack_frame) * 8); |
|
|
|
current->function_stack_top = 0; |
|
|
|
@ -449,12 +462,11 @@ int ink_push_fn(struct context* ctx, struct stack_frame value) { |
|
|
|
void* renewed; |
|
|
|
new_count = (current->function_stack_capacity + current->function_stack_capacity/2); |
|
|
|
renewed = ctx->realloc(ctx, current->function_stack, sizeof(struct stack_frame) * new_count); |
|
|
|
if(renewed == NULL) { |
|
|
|
if(routine_assert(ctx, renewed == NULL, -9, "Failed to reallocate (ink_push_fn)")) { |
|
|
|
return -9; |
|
|
|
} else { |
|
|
|
current->function_stack = renewed; |
|
|
|
current->function_stack_capacity = new_count; |
|
|
|
} |
|
|
|
current->function_stack = renewed; |
|
|
|
current->function_stack_capacity = new_count; |
|
|
|
} |
|
|
|
current->function_stack[current->function_stack_top] = value; |
|
|
|
current->function_stack_top++; |
|
|
|
@ -696,7 +708,7 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
} |
|
|
|
if(done) { |
|
|
|
err = ink_push(pContext, value); |
|
|
|
if(err < 0) { |
|
|
|
if(routine_assert(pContext, err < 0, -19, "Failed to push in the context.")) { |
|
|
|
return -19; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -717,7 +729,7 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
value.value = i; |
|
|
|
value.type = INK_FUNCTION; |
|
|
|
err = ink_push(pContext, value); |
|
|
|
if(err < 0) { |
|
|
|
if(routine_assert(pContext, err < 0, -20, "Failed to push in the context.")) { |
|
|
|
return -20; |
|
|
|
} |
|
|
|
done = 1; |
|
|
|
@ -732,7 +744,7 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
value.value = i; |
|
|
|
value.type = INK_NATIVE_FUNCTION; |
|
|
|
err = ink_push(pContext, value); |
|
|
|
if(err < 0) { |
|
|
|
if(routine_assert(pContext, err < 0, -21, "Failed to push in the context.")) { |
|
|
|
return -21; |
|
|
|
} |
|
|
|
done = 1; |
|
|
|
@ -749,7 +761,7 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
value.value = atoi(r); |
|
|
|
value.type = INK_INTEGER; |
|
|
|
err = ink_push(pContext, value); |
|
|
|
if(err < 0) { |
|
|
|
if(routine_assert(pContext, err < 0, -22, "Failed to push in the context.")) { |
|
|
|
return -22; |
|
|
|
} |
|
|
|
done = 1; |
|
|
|
@ -929,6 +941,9 @@ int ink_make_routine(struct context* ctx) { |
|
|
|
} |
|
|
|
} |
|
|
|
/* FIXME: Maybe we need to abort here, this seems like quite an unsteady state */ |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
routine_assert(ctx, 0, -758, "FIXME reached: Maybe we need to abort here, this seems like quite an unsteady state"); |
|
|
|
#endif |
|
|
|
return -758; |
|
|
|
} |
|
|
|
|
|
|
|
@ -955,6 +970,13 @@ int ink_kill_routine(struct context* ctx, int routine){ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef LABEL_BUFFER |
|
|
|
#define LABEL_BUFFER 128 |
|
|
|
#endif |
|
|
|
#ifndef FUNCTION_BUFFER |
|
|
|
#define FUNCTION_BUFFER 256 |
|
|
|
#endif |
|
|
|
|
|
|
|
/** |
|
|
|
* |
|
|
|
* @param pContext |
|
|
|
@ -972,8 +994,6 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
|
|
|
int err; |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
#define LABEL_BUFFER 128 |
|
|
|
#define FUNCTION_BUFFER 256 |
|
|
|
struct label labels[LABEL_BUFFER]; |
|
|
|
struct elem function_buffer[FUNCTION_BUFFER]; |
|
|
|
/* TODO: add checks for overflows in these arrays */ |
|
|
|
@ -1113,9 +1133,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
err = ink_add_indigenous(pContext, pContext->lex_reserved_words[function_name.value], function_buffer, function_buffer_top); |
|
|
|
} else { |
|
|
|
if(function_name.type == INK_NATIVE_FUNCTION) { |
|
|
|
err = ink_add_indigenous_already_array(pContext, pContext->native_words[function_name.value].name,function_buffer, function_buffer_top); |
|
|
|
err = ink_add_indigenous_already_array(pContext, pContext->native_words[function_name.value].name, function_buffer, function_buffer_top); |
|
|
|
} else if(function_name.type == INK_FUNCTION) { |
|
|
|
err = ink_add_indigenous_already_array(pContext, pContext->words[function_name.value].name,function_buffer, function_buffer_top); |
|
|
|
err = ink_add_indigenous_already_array(pContext, pContext->words[function_name.value].name, function_buffer, function_buffer_top); |
|
|
|
} |
|
|
|
} |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
@ -1220,7 +1240,7 @@ int ink_step(struct context *pContext) { |
|
|
|
} else { |
|
|
|
top->index++; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(pContext->native_words_top <= top->executing.value) { |
|
|
|
if(routine_assert(pContext, pContext->native_words_top <= top->executing.value, -3438, "Bytecode contained out of bound executable word")) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Bytecode contained out of bound executable word"; |
|
|
|
pContext->panic = 1; |
|
|
|
@ -1232,7 +1252,7 @@ int ink_step(struct context *pContext) { |
|
|
|
break; |
|
|
|
case INK_FUNCTION: |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(pContext->words_top <= top->executing.value) { |
|
|
|
if(routine_assert(pContext, pContext->words_top <= top->executing.value, -78611, "Bytecode contained out of bound artificial word")) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Bytecode contained out of bound artificial word"; |
|
|
|
pContext->panic = 1; |
|
|
|
@ -1251,7 +1271,7 @@ int ink_step(struct context *pContext) { |
|
|
|
frame.index = 0; |
|
|
|
t = ink_push_fn(pContext, frame); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(t < 0) { |
|
|
|
if(routine_assert(pContext, t < 0, -3583, "Instruction pointer underflow")) { |
|
|
|
pContext->panic = 1; |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Instruction pointer underflow"; |
|
|
|
@ -1264,7 +1284,7 @@ int ink_step(struct context *pContext) { |
|
|
|
default: |
|
|
|
t = ink_push(pContext, top->executing); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(t < 0) { |
|
|
|
if(routine_assert(pContext, t < 0, -25, "Literal token could not be pushed")) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Literal token could not be pushed"; |
|
|
|
pContext->panic = 1; |
|
|
|
@ -1745,16 +1765,14 @@ static void add_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -312; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -312, "`+` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = -684; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -684, "`+` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1768,16 +1786,14 @@ static void sub_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -2581; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -2581, "`-` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -821; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -821, "`-` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1791,16 +1807,14 @@ static void mult_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -8533; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -8533, "`*` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -543; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -543, "`*` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1814,16 +1828,14 @@ static void div_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -84; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -84, "`/` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -1328; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -1328, "`/` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1838,8 +1850,7 @@ static void is_equal(struct context* ctx) { |
|
|
|
struct elem ret; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -13587; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -13587, "`==` requires 2 operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1859,8 +1870,7 @@ static void is_different(struct context* ctx) { |
|
|
|
struct elem ret; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -3873; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -3873, "`!=` requires 2 operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1881,16 +1891,14 @@ static void rem_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -218; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -218, "`%` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -8321; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -8321, "`%` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1904,16 +1912,14 @@ static void xor_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -184; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -184, "`int.xor` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -183; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -183, "`int.xor` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -1927,16 +1933,14 @@ static void gt_int(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -132; |
|
|
|
if(routine_assert(ctx, currentRoutine->top < 2, -132, "`>` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
currentRoutine->panic = -1185; |
|
|
|
if(routine_assert(ctx, !(a.type == INK_INTEGER && b.type == INK_INTEGER), -1185, "`>` requires 2 integer operands")) { |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
@ -2662,6 +2666,124 @@ static void arrayify_stack(struct context* ctx) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void print_string(struct context* ctx, const struct elem string) { |
|
|
|
int i; |
|
|
|
const struct ink_array* name = ink_get_value(ctx, string); |
|
|
|
for (i = 0; i < name->top; ++i) { |
|
|
|
const struct elem a = name->elements[i]; |
|
|
|
if(a.value <= 0x7F) { |
|
|
|
ctx->putchar(ctx, a.value); |
|
|
|
} else if(a.value <= 0x7FF) { |
|
|
|
ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 192); |
|
|
|
ctx->putchar(ctx, (a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0xFFFF) { |
|
|
|
ctx->putchar(ctx, ((a.value & 0x3F000) >> 12) | 224); |
|
|
|
ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar(ctx, (a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0x10FFFF) { |
|
|
|
ctx->putchar(ctx, ((a.value & 0x3C0000) >> 18) | 240); |
|
|
|
ctx->putchar(ctx, ((a.value & 0x3F000) >> 12) | 128); |
|
|
|
ctx->putchar(ctx, ((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar(ctx, (a.value & 0x3F) | 128); |
|
|
|
} else { |
|
|
|
ctx->panic = -9472; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void list_words(struct context* ctx) { |
|
|
|
struct native_fn* nit; |
|
|
|
struct fn* dit; |
|
|
|
for(nit = ctx->native_words; nit != ctx->native_words + ctx->native_words_top; ++nit) { |
|
|
|
print_string(ctx, nit->name); |
|
|
|
ctx->putchar(ctx, '\n'); |
|
|
|
} |
|
|
|
for(dit = ctx->words; dit != ctx->words + ctx->words_top; ++dit) { |
|
|
|
print_string(ctx, dit->name); |
|
|
|
ctx->putchar(ctx, '\n'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void resolve_word(struct context* ctx) { |
|
|
|
struct native_fn* nit; |
|
|
|
struct fn* dit; |
|
|
|
int i; |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct elem a; |
|
|
|
struct ink_array *ary; |
|
|
|
int found = 0; |
|
|
|
|
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
int tid; |
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#endif |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top - 1].type != tid) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
ary = ink_get_value(ctx, a); |
|
|
|
|
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
for(i = 0; i < ary->top; ++i) { |
|
|
|
if(ary->elements[i].type != INK_INTEGER) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
|
|
|
|
for(nit = ctx->native_words; (!found) && nit != ctx->native_words + ctx->native_words_top; ++nit) { |
|
|
|
struct ink_array* inner_name = ink_get_value(ctx, nit->name); |
|
|
|
if(ary->top == inner_name->top && memcmp(ary->elements, inner_name->elements, sizeof(struct elem)*ary->top) == 0) { |
|
|
|
struct elem fn; |
|
|
|
fn.type = INK_NATIVE_FUNCTION; |
|
|
|
fn.value = nit - ctx->native_words; |
|
|
|
ink_push(ctx, fn); |
|
|
|
found = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
for(dit = ctx->words; (!found) && dit != ctx->words + ctx->words_top; ++dit) { |
|
|
|
const struct ink_array* inner_name = ink_get_value(ctx, dit->name); |
|
|
|
if(ary->top == inner_name->top && memcmp(ary->elements, inner_name->elements, sizeof(struct elem)*ary->top) == 0) { |
|
|
|
struct elem fn; |
|
|
|
fn.type = INK_FUNCTION; |
|
|
|
fn.value = dit - ctx->words; |
|
|
|
ink_push(ctx, fn); |
|
|
|
found = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void call_word(struct context* ctx) { |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct stack_frame frame; |
|
|
|
|
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 1 || (currentRoutine->stack[currentRoutine->top - 1].type != INK_FUNCTION && currentRoutine->stack[currentRoutine->top - 1].type != INK_NATIVE_FUNCTION)) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
frame.executing = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
frame.index = 0; |
|
|
|
ink_pop(ctx); |
|
|
|
ink_push_fn(ctx, frame); |
|
|
|
} |
|
|
|
|
|
|
|
static void static_EOF(struct context* ctx) { |
|
|
|
struct elem e; |
|
|
|
e.type = INK_INTEGER; |
|
|
|
e.value = EOF; |
|
|
|
ink_push(ctx, e); |
|
|
|
} |
|
|
|
|
|
|
|
int ink_std_library(struct context* ctx) { |
|
|
|
int v; |
|
|
|
v = 0; |
|
|
|
@ -2703,6 +2825,10 @@ int ink_std_library(struct context* ctx) { |
|
|
|
v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints); |
|
|
|
v += ink_add_native(ctx, "is.array", is_array); |
|
|
|
v += ink_add_native(ctx, "stack.to_array", arrayify_stack); |
|
|
|
v += ink_add_native(ctx, "words?", list_words); |
|
|
|
v += ink_add_native(ctx, "words!", resolve_word); |
|
|
|
v += ink_add_native(ctx, "words.call", call_word); |
|
|
|
v += ink_add_native(ctx, "EOF", static_EOF); |
|
|
|
|
|
|
|
return v; |
|
|
|
} |
|
|
|
|