|
|
@ -240,12 +240,14 @@ int ink_push(struct context* ctx, struct elem value) { |
|
|
|
void* renewed; |
|
|
|
new_count = (current->capacity + current->capacity/2); |
|
|
|
renewed = ctx->realloc(ctx, current->stack, sizeof(struct elem) * new_count); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(renewed == NULL) { |
|
|
|
return -18; |
|
|
|
} else { |
|
|
|
current->stack = renewed; |
|
|
|
current->capacity = new_count; |
|
|
|
} |
|
|
|
#endif |
|
|
|
current->stack = renewed; |
|
|
|
current->capacity = new_count; |
|
|
|
|
|
|
|
} |
|
|
|
current->stack[current->top] = value; |
|
|
|
current->top++; |
|
|
@ -424,10 +426,12 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
} |
|
|
|
value = routine->stack[routine->top - 1]; |
|
|
|
ary = ink_get_value(pContext, value); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ary == NULL) { |
|
|
|
pContext->panic = -1; |
|
|
|
return -8747; |
|
|
|
} |
|
|
|
#endif |
|
|
|
for(;it != *end;++it) { |
|
|
|
struct elem character; |
|
|
|
character.type = INK_INTEGER; |
|
|
@ -527,9 +531,11 @@ static int ink_consume_one(int* end, struct context* pContext, char* r, int is_s |
|
|
|
value.type = INK_RESERVED; |
|
|
|
} |
|
|
|
err = ink_push(pContext, value); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) { |
|
|
|
return -23; |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
*end = 0; |
|
|
|
return 0; |
|
|
@ -578,7 +584,7 @@ static int ink_lex(struct context *pContext, const char* buffer) { |
|
|
|
r[end] = *buffer; |
|
|
|
++end; |
|
|
|
} |
|
|
|
} else /* ... */ |
|
|
|
} else /* go on parsing something else if it is not a string, like this to be able to disable strings */ |
|
|
|
#endif |
|
|
|
if(isspace(*buffer)) { |
|
|
|
if(end == 1 && r[0] == '#') { |
|
|
@ -589,10 +595,12 @@ static int ink_lex(struct context *pContext, const char* buffer) { |
|
|
|
goto restart_after_comment; |
|
|
|
} |
|
|
|
err = ink_consume_one(&end, pContext, r, 0); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) { |
|
|
|
pContext->panic = 1; |
|
|
|
return -8; |
|
|
|
} |
|
|
|
#endif |
|
|
|
} else /* ... */ |
|
|
|
#ifndef NOSTRINGLITERALS |
|
|
|
if(end == 0 && *buffer == '"' && !parses_string) { |
|
|
@ -606,10 +614,12 @@ static int ink_lex(struct context *pContext, const char* buffer) { |
|
|
|
++buffer; |
|
|
|
} |
|
|
|
err = ink_consume_one(&end, pContext, r, 0); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) { |
|
|
|
pContext->panic = 1; |
|
|
|
return -9; |
|
|
|
} |
|
|
|
#endif |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@ -647,22 +657,23 @@ int ink_make_routine(struct context* ctx) { |
|
|
|
void* renewed; |
|
|
|
new_count = (ctx->routines_capacity + ctx->routines_capacity/2); |
|
|
|
renewed = ctx->inner_realloc(ctx, ctx->routines, sizeof(struct ink_routine) * new_count); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(renewed == NULL) { |
|
|
|
return -99; |
|
|
|
} else { |
|
|
|
ctx->routines = renewed; |
|
|
|
it = ctx->routines + ctx->routines_capacity; |
|
|
|
end = ctx->routines + new_count; |
|
|
|
for(;it != end;++it) { |
|
|
|
it->stack = NULL; |
|
|
|
it->function_stack = NULL; |
|
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
it->parse_error.is_set = 0; |
|
|
|
it->runtime_error.is_set = 0; |
|
|
|
} |
|
|
|
ctx->routines_capacity = new_count; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
ctx->routines = renewed; |
|
|
|
it = ctx->routines + ctx->routines_capacity; |
|
|
|
end = ctx->routines + new_count; |
|
|
|
for(;it != end;++it) { |
|
|
|
it->stack = NULL; |
|
|
|
it->function_stack = NULL; |
|
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
it->parse_error.is_set = 0; |
|
|
|
it->runtime_error.is_set = 0; |
|
|
|
} |
|
|
|
ctx->routines_capacity = new_count; |
|
|
|
} |
|
|
|
|
|
|
|
it = ctx->routines; |
|
|
|
end = ctx->routines + ctx->routines_capacity; |
|
|
@ -716,7 +727,11 @@ int ink_kill_routine(struct context* ctx, int routine){ |
|
|
|
static int ink_parse(struct context* pContext, struct elem* executable_buffer, int* executable_buffer_top) { |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
int i, function_buffer_top, function_name, mode; |
|
|
|
#pragma GCC diagnostic push |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
|
|
|
#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]; |
|
|
@ -742,6 +757,7 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
mode = MODE_FUNCTION; |
|
|
|
function_name = -1; |
|
|
|
goto next_token; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
case INK_DO_KW: |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Found start of function body unexpectedly"; |
|
|
@ -752,6 +768,7 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
currentRoutine->parse_error.error_message = "Found end of function unexpectedly"; |
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
|
return -26; |
|
|
|
#endif |
|
|
|
default: |
|
|
|
executable_buffer[*executable_buffer_top] = current; |
|
|
|
*executable_buffer_top += 1; |
|
|
@ -759,17 +776,19 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
break; |
|
|
|
case MODE_FUNCTION: |
|
|
|
if(current.type == INK_DO_KW) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(function_name == -1) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Found start of function body before the name of the function was provided"; |
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
|
return -27; |
|
|
|
} else { |
|
|
|
mode = MODE_DO; |
|
|
|
memset(labels, 0, sizeof(struct label)*128); |
|
|
|
goto next_token; |
|
|
|
} |
|
|
|
#endif |
|
|
|
mode = MODE_DO; |
|
|
|
memset(labels, 0, sizeof(struct label)*128); |
|
|
|
goto next_token; |
|
|
|
} |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(function_name != -1) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Function name was not found"; |
|
|
@ -782,6 +801,7 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
|
return -29; |
|
|
|
} |
|
|
|
#endif |
|
|
|
function_name = current.value; |
|
|
|
break; |
|
|
|
case MODE_DO: |
|
|
@ -794,6 +814,7 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
int k; |
|
|
|
for(k = 0; k < LABEL_BUFFER; k++) { |
|
|
|
if(labels[k].active) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) { |
|
|
|
labels[k].dest = j; |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
@ -802,6 +823,7 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
return -30; |
|
|
|
break; |
|
|
|
} |
|
|
|
#endif |
|
|
|
} else { |
|
|
|
labels[k].active = 1; |
|
|
|
labels[k].name = pContext->lex_reserved_words[pt.value]; |
|
|
@ -835,10 +857,12 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
} |
|
|
|
} |
|
|
|
err = ink_add_indigenous(pContext, pContext->lex_reserved_words[function_name], function_buffer, function_buffer_top); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) { |
|
|
|
pContext->panic = 1; |
|
|
|
return -33; |
|
|
|
} |
|
|
|
#endif |
|
|
|
function_buffer_top = 0; |
|
|
|
mode = MODE_EXECUTABLE; |
|
|
|
goto next_token; |
|
|
@ -849,12 +873,14 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
|
} |
|
|
|
next_token: i=i; |
|
|
|
} |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(mode == MODE_FUNCTION || mode == MODE_DO) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Expected a function to be complete"; |
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
|
return -32; |
|
|
|
} |
|
|
|
#endif |
|
|
|
return 0; |
|
|
|
#undef MODE_EXECUTABLE |
|
|
|
#undef MODE_FUNCTION |
|
|
@ -885,22 +911,26 @@ int ink_step(struct context *pContext) { |
|
|
|
ink_pop_fn(pContext); |
|
|
|
} else { |
|
|
|
top->index++; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(pContext->native_words_top <= top->executing.value) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Bytecode contained out of bound executable word"; |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
pContext->native_words[top->executing.value].value(pContext); |
|
|
|
} |
|
|
|
break; |
|
|
|
case INK_FUNCTION: |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(pContext->words_top <= top->executing.value) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Bytecode contained out of bound artificial word"; |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
if(top->index >= pContext->words[top->executing.value].size) { |
|
|
|
ink_pop_fn(pContext); |
|
|
|
} else { |
|
|
@ -912,23 +942,27 @@ int ink_step(struct context *pContext) { |
|
|
|
frame.executing = next; |
|
|
|
frame.index = 0; |
|
|
|
t = ink_push_fn(pContext, frame); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(t < 0) { |
|
|
|
pContext->panic = 1; |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Instruction pointer underflow"; |
|
|
|
return -11; |
|
|
|
} |
|
|
|
#endif |
|
|
|
top->index++; |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
t = ink_push(pContext, top->executing); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(t < 0) { |
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
currentRoutine->runtime_error.error_message = "Literal token could not be pushed"; |
|
|
|
pContext->panic = 1; |
|
|
|
return -25; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop_fn(pContext); |
|
|
|
break; |
|
|
|
} |
|
|
@ -955,22 +989,26 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
|
currentRoutine->capacity = 0; |
|
|
|
err = ink_lex(pContext, buffer); |
|
|
|
if(err < 0) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!currentRoutine->parse_error.is_set) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Unknown lexer error"; |
|
|
|
currentRoutine->parse_error.offset = -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
executable_buffer_top = 0; |
|
|
|
err = ink_parse(pContext, executable_buffer, &executable_buffer_top); |
|
|
|
if(err < 0) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!currentRoutine->parse_error.is_set) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Unknown parser error"; |
|
|
|
currentRoutine->parse_error.offset = -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
@ -983,11 +1021,13 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
|
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) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(!currentRoutine->parse_error.is_set) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
currentRoutine->parse_error.error_message = "Could not start execution: no valid way to create a frame"; |
|
|
|
currentRoutine->parse_error.offset = -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
@ -995,6 +1035,7 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
|
frame.index = 0; |
|
|
|
err = ink_push_fn(pContext, frame); |
|
|
|
pContext->routines[pContext->routine_current].top = 0; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (err < 0) { |
|
|
|
if(!currentRoutine->parse_error.is_set) { |
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
@ -1004,6 +1045,7 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
|
pContext->panic = 1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
} else { |
|
|
|
pContext->routines[pContext->routine_current].panic = INK_ROUTINE_SUCCESS; |
|
|
|
} |
|
|
@ -1102,13 +1144,17 @@ int ink_new_type( |
|
|
|
|
|
|
|
static struct element_slab* ink_get_value_link(struct context* ctx, struct elem ref) { |
|
|
|
int type_id; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ref.type < 16) return NULL; |
|
|
|
#endif |
|
|
|
type_id = ref.type - 16; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
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; |
|
|
|
#endif |
|
|
|
return ctx->types[type_id].elements + ref.value; |
|
|
|
} |
|
|
|
|
|
|
@ -1350,16 +1396,20 @@ static void add_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = a.value + b.value; |
|
|
|
} |
|
|
@ -1369,16 +1419,20 @@ static void sub_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value - a.value; |
|
|
|
} |
|
|
@ -1388,16 +1442,20 @@ static void mult_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value * a.value; |
|
|
|
} |
|
|
@ -1407,16 +1465,20 @@ static void div_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value; |
|
|
|
} |
|
|
@ -1427,10 +1489,12 @@ static void is_equal(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
struct elem ret; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
ink_pop(ctx); |
|
|
@ -1446,10 +1510,12 @@ static void is_different(struct context* ctx) { |
|
|
|
struct elem b; |
|
|
|
struct elem ret; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
ink_pop(ctx); |
|
|
@ -1466,16 +1532,20 @@ static void rem_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value; |
|
|
|
} |
|
|
@ -1485,16 +1555,20 @@ static void xor_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value ^ a.value; |
|
|
|
} |
|
|
@ -1504,16 +1578,20 @@ static void gt_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value > a.value; |
|
|
|
} |
|
|
@ -1523,16 +1601,20 @@ static void gte_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value >= a.value; |
|
|
|
} |
|
|
@ -1542,16 +1624,20 @@ static void lte_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value <= a.value; |
|
|
|
} |
|
|
@ -1563,16 +1649,20 @@ static void lt_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
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 = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value < a.value; |
|
|
|
} |
|
|
@ -1580,49 +1670,72 @@ static void lt_int(struct context* ctx) { |
|
|
|
static void dupe_elem(struct context* ctx) { |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
struct elem a; |
|
|
|
int err; |
|
|
|
#pragma GCC diagnostic push |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
|
|
|
int err; |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
err = ink_push(ctx, a); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) ctx->panic = 1; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static void drop_elem(struct context* ctx) { |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
static void pluck_elem(struct context* ctx) { |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
struct elem a; |
|
|
|
int position, err; |
|
|
|
int position; |
|
|
|
#pragma GCC diagnostic push |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
|
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" |
|
|
|
int err; |
|
|
|
#pragma GCC diagnostic pop |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
position = currentRoutine->top - (a.value + 1); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(position >= currentRoutine->top || position < 0) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
err = ink_push(ctx, currentRoutine->stack[position]); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(err < 0) ctx->panic = 1; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static void swap_elem(struct context* ctx) { |
|
|
@ -1630,10 +1743,12 @@ static void swap_elem(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
struct elem b; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
currentRoutine->stack[currentRoutine->top-2] = a; |
|
|
@ -1644,15 +1759,19 @@ static void return_if(struct context* ctx) { |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
struct elem a; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
ctx->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
if(a.value) { |
|
|
|
ink_pop_fn(ctx); |
|
|
|
ink_pop_fn(ctx); |
|
|
@ -1666,16 +1785,20 @@ static void jump_if(struct context* ctx) { |
|
|
|
struct elem label; |
|
|
|
struct elem condition; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
ctx->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
label = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
condition = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(label.type != INK_INTEGER || condition.type != INK_INTEGER) { |
|
|
|
ctx->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
ink_pop(ctx); |
|
|
|
ink_pop_fn(ctx); |
|
|
@ -1692,10 +1815,12 @@ static void print_int(struct context* ctx) { |
|
|
|
char* n; |
|
|
|
char* str; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
ink_pop(ctx); |
|
|
|
n = ink_itoa(ctx, a.value); |
|
|
@ -1712,10 +1837,12 @@ static void print_as_utf8(struct context* ctx) { |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
struct elem a; |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) { |
|
|
|
ctx->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
if(a.value <= 0x7F) { |
|
|
|
ctx->putchar(ctx, a.value); |
|
|
@ -1884,22 +2011,28 @@ void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct |
|
|
|
} |
|
|
|
|
|
|
|
static void push_array(struct context* ctx) { |
|
|
|
int tid; |
|
|
|
struct elem a; |
|
|
|
struct ink_routine* currentRoutine; |
|
|
|
struct ink_array* ary; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
int tid; |
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#endif |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 2 || 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 |
|
|
|
if(ary == NULL) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
array_push(ctx, currentRoutine, ary, currentRoutine->stack[currentRoutine->top-1]); |
|
|
|
ink_pop(ctx); |
|
|
@ -1912,10 +2045,12 @@ static void push_delimited_array(struct context* ctx) { |
|
|
|
struct ink_array* ary; |
|
|
|
tid = get_type_by_name(ctx, "array_marker"); |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
new_array(ctx); |
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
ink_pop(ctx); |
|
|
@ -1933,10 +2068,12 @@ static void push_delimited_array(struct context* ctx) { |
|
|
|
idx -= 1; |
|
|
|
|
|
|
|
ary->elements = malloc(sizeof(struct elem) * idx); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ary->elements == NULL) { |
|
|
|
currentRoutine->panic = -541; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ary->capacity = idx; |
|
|
|
ary->top = 0; |
|
|
|
|
|
|
@ -1956,65 +2093,80 @@ static void push_delimited_array(struct context* ctx) { |
|
|
|
} |
|
|
|
|
|
|
|
static void index_array(struct context* ctx) { |
|
|
|
int tid; |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct elem a; |
|
|
|
struct ink_array *ary; |
|
|
|
struct elem idx; |
|
|
|
|
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
int tid; |
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#endif |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 2 || currentRoutine->stack[currentRoutine->top - 1].type != tid || currentRoutine->stack[currentRoutine->top - 2].type != INK_INTEGER) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
ary = ink_get_value(ctx, a); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (ary == NULL) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
|
|
|
|
idx = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
ink_pop(ctx); |
|
|
|
|
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ary->top <= idx.value) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
ink_push(ctx, ary->elements[idx.value]); |
|
|
|
} |
|
|
|
|
|
|
|
static void set_array(struct context* ctx) { |
|
|
|
int tid; |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct elem a; |
|
|
|
struct ink_array *ary; |
|
|
|
struct elem idx; |
|
|
|
struct elem value; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
int tid; |
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#endif |
|
|
|
|
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 3 || currentRoutine->stack[currentRoutine->top - 1].type != tid || currentRoutine->stack[currentRoutine->top - 2].type != INK_INTEGER) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
ary = ink_get_value(ctx, a); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (ary == NULL) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
idx = currentRoutine->stack[currentRoutine->top - 2]; |
|
|
|
value = currentRoutine->stack[currentRoutine->top - 3]; |
|
|
|
|
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ary->top <= idx.value) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
ink_pop(ctx); |
|
|
|
ink_pop(ctx); |
|
|
@ -2024,24 +2176,30 @@ static void set_array(struct context* ctx) { |
|
|
|
} |
|
|
|
|
|
|
|
static void get_size_array(struct context* ctx) { |
|
|
|
int tid; |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct elem a; |
|
|
|
struct ink_array *ary; |
|
|
|
struct elem sz; |
|
|
|
|
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#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 |
|
|
|
if (ary == NULL) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
|
|
|
|
sz.type = INK_INTEGER; |
|
|
@ -2057,10 +2215,12 @@ static void is_array(struct context* ctx) { |
|
|
|
|
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 1) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a.type = INK_INTEGER; |
|
|
|
a.value = currentRoutine->stack[currentRoutine->top - 1].type == tid; |
|
|
|
ink_pop(ctx); |
|
|
@ -2073,10 +2233,12 @@ static void is_int(struct context* ctx) { |
|
|
|
struct elem a; |
|
|
|
|
|
|
|
currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if (currentRoutine->top < 1) { |
|
|
|
currentRoutine->panic = -1; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
a.type = INK_INTEGER; |
|
|
|
a.value = currentRoutine->stack[currentRoutine->top - 1].type == INK_INTEGER; |
|
|
|
ink_pop(ctx); |
|
|
@ -2085,26 +2247,33 @@ static void is_int(struct context* ctx) { |
|
|
|
} |
|
|
|
|
|
|
|
static void print_array_of_codepoints(struct context* ctx) { |
|
|
|
int tid, i; |
|
|
|
int i; |
|
|
|
struct ink_routine *currentRoutine; |
|
|
|
struct elem a; |
|
|
|
struct ink_array *ary; |
|
|
|
|
|
|
|
tid = get_type_by_name(ctx, "array"); |
|
|
|
#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(i = 0; i < ary->top; ++i) { |
|
|
|
ink_push(ctx, ary->elements[i]); |
|
|
@ -2122,10 +2291,12 @@ static void arrayify_stack(struct context* ctx) { |
|
|
|
if(currentRoutine->panic < 0) return; |
|
|
|
array_ref = currentRoutine->stack[currentRoutine->top - 1]; |
|
|
|
ary = ink_get_value(ctx, array_ref); |
|
|
|
#ifndef NOEXTRACHECKS |
|
|
|
if(ary == NULL) { |
|
|
|
currentRoutine->panic = -717; |
|
|
|
return; |
|
|
|
} |
|
|
|
#endif |
|
|
|
ink_pop(ctx); |
|
|
|
for(idx = 0; idx < currentRoutine->top; ++idx) { |
|
|
|
array_push(ctx, currentRoutine, ary, currentRoutine->stack[idx]); |
|
|
@ -2185,4 +2356,4 @@ int ink_std_library(struct context* ctx) { |
|
|
|
#endif /* NOARRAYLIB */ |
|
|
|
|
|
|
|
return v; |
|
|
|
} |
|
|
|
} |