|
@ -21,6 +21,8 @@ |
|
|
#define _KEYWORD_INK_END "end" |
|
|
#define _KEYWORD_INK_END "end" |
|
|
#define _KEYWORD_INK_RETURN "return" |
|
|
#define _KEYWORD_INK_RETURN "return" |
|
|
|
|
|
|
|
|
|
|
|
#define INK_ARRAY_FLAG_PROTECTED 1 |
|
|
|
|
|
|
|
|
#define min(x, y) ((x) > (y) ? (y) : (x)) |
|
|
#define min(x, y) ((x) > (y) ? (y) : (x)) |
|
|
#define max(x, y) ((x) < (y) ? (y) : (x)) |
|
|
#define max(x, y) ((x) < (y) ? (y) : (x)) |
|
|
|
|
|
|
|
@ -591,6 +593,8 @@ int ink_make_routine(struct context* ctx) { |
|
|
it->stack = NULL; |
|
|
it->stack = NULL; |
|
|
it->function_stack = NULL; |
|
|
it->function_stack = NULL; |
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
|
|
it->parse_error.is_set = 0; |
|
|
|
|
|
it->runtime_error.is_set = 0; |
|
|
} |
|
|
} |
|
|
} else if(ctx->routines_top == ctx->routines_capacity) { |
|
|
} else if(ctx->routines_top == ctx->routines_capacity) { |
|
|
int new_count; |
|
|
int new_count; |
|
@ -604,7 +608,11 @@ int ink_make_routine(struct context* ctx) { |
|
|
it = ctx->routines + ctx->routines_capacity; |
|
|
it = ctx->routines + ctx->routines_capacity; |
|
|
end = ctx->routines + new_count; |
|
|
end = ctx->routines + new_count; |
|
|
for(;it != end;++it) { |
|
|
for(;it != end;++it) { |
|
|
|
|
|
it->stack = NULL; |
|
|
|
|
|
it->function_stack = NULL; |
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
|
|
it->parse_error.is_set = 0; |
|
|
|
|
|
it->runtime_error.is_set = 0; |
|
|
} |
|
|
} |
|
|
ctx->routines_capacity = new_count; |
|
|
ctx->routines_capacity = new_count; |
|
|
} |
|
|
} |
|
@ -617,12 +625,9 @@ int ink_make_routine(struct context* ctx) { |
|
|
if(it->panic == INK_ROUTINE_CAN_REUSE) { |
|
|
if(it->panic == INK_ROUTINE_CAN_REUSE) { |
|
|
int idx; |
|
|
int idx; |
|
|
it->panic = 0; |
|
|
it->panic = 0; |
|
|
it->stack = NULL; |
|
|
|
|
|
it->top = 0; |
|
|
it->top = 0; |
|
|
it->capacity = 0; |
|
|
|
|
|
it->function_stack = NULL; |
|
|
|
|
|
it->function_stack_top = 0; |
|
|
it->function_stack_top = 0; |
|
|
it->function_stack_capacity = 0; |
|
|
|
|
|
|
|
|
|
|
|
idx = it - ctx->routines; |
|
|
idx = it - ctx->routines; |
|
|
if(idx >= ctx->routines_top) { |
|
|
if(idx >= ctx->routines_top) { |
|
|
ctx->routines_top = idx + 1; |
|
|
ctx->routines_top = idx + 1; |
|
@ -630,6 +635,7 @@ int ink_make_routine(struct context* ctx) { |
|
|
return idx; |
|
|
return idx; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* FIXME: Maybe we need to abort here, this seems like quite an unsteady state */ |
|
|
return -758; |
|
|
return -758; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -691,7 +697,14 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
function_name = -1; |
|
|
function_name = -1; |
|
|
goto next_token; |
|
|
goto next_token; |
|
|
case INK_DO_KW: |
|
|
case INK_DO_KW: |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Found start of function body unexpectedly"; |
|
|
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
|
|
|
return -26; |
|
|
case INK_END_KW: |
|
|
case INK_END_KW: |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Found end of function unexpectedly"; |
|
|
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
return -26; |
|
|
return -26; |
|
|
default: |
|
|
default: |
|
|
executable_buffer[*executable_buffer_top] = current; |
|
|
executable_buffer[*executable_buffer_top] = current; |
|
@ -701,6 +714,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
case MODE_FUNCTION: |
|
|
case MODE_FUNCTION: |
|
|
if(current.type == INK_DO_KW) { |
|
|
if(current.type == INK_DO_KW) { |
|
|
if(function_name == -1) { |
|
|
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; |
|
|
return -27; |
|
|
} else { |
|
|
} else { |
|
|
mode = MODE_DO; |
|
|
mode = MODE_DO; |
|
@ -709,9 +725,15 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
if(function_name != -1) { |
|
|
if(function_name != -1) { |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Function name was not found"; |
|
|
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
return -28; |
|
|
return -28; |
|
|
} |
|
|
} |
|
|
if(current.type != INK_RESERVED) { |
|
|
if(current.type != INK_RESERVED) { |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Expected special token"; |
|
|
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
return -29; |
|
|
return -29; |
|
|
} |
|
|
} |
|
|
function_name = current.value; |
|
|
function_name = current.value; |
|
@ -728,6 +750,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
if(labels[k].active) { |
|
|
if(labels[k].active) { |
|
|
if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) { |
|
|
if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) { |
|
|
labels[k].dest = j; |
|
|
labels[k].dest = j; |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Label duplicate label in function"; |
|
|
|
|
|
currentRoutine->parse_error.offset= i; |
|
|
return -30; |
|
|
return -30; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -779,6 +804,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
next_token: i=i; |
|
|
next_token: i=i; |
|
|
} |
|
|
} |
|
|
if(mode == MODE_FUNCTION || mode == MODE_DO) { |
|
|
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; |
|
|
return -32; |
|
|
} |
|
|
} |
|
|
return 0; |
|
|
return 0; |
|
@ -812,6 +840,8 @@ int ink_step(struct context *pContext) { |
|
|
} else { |
|
|
} else { |
|
|
top->index++; |
|
|
top->index++; |
|
|
if(pContext->native_words_top <= top->executing.value) { |
|
|
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; |
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@ -820,7 +850,9 @@ int ink_step(struct context *pContext) { |
|
|
break; |
|
|
break; |
|
|
case INK_FUNCTION: |
|
|
case INK_FUNCTION: |
|
|
if(pContext->words_top <= top->executing.value) { |
|
|
if(pContext->words_top <= top->executing.value) { |
|
|
pContext->panic = 1; |
|
|
|
|
|
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
|
|
currentRoutine->runtime_error.error_message = "Bytecode contained out of bound artificial word"; |
|
|
|
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
if(top->index >= pContext->words[top->executing.value].size) { |
|
|
if(top->index >= pContext->words[top->executing.value].size) { |
|
@ -836,6 +868,8 @@ int ink_step(struct context *pContext) { |
|
|
t = ink_push_fn(pContext, frame); |
|
|
t = ink_push_fn(pContext, frame); |
|
|
if(t < 0) { |
|
|
if(t < 0) { |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
|
|
currentRoutine->runtime_error.error_message = "Instruction pointer underflow"; |
|
|
return -11; |
|
|
return -11; |
|
|
} |
|
|
} |
|
|
top->index++; |
|
|
top->index++; |
|
@ -844,6 +878,8 @@ int ink_step(struct context *pContext) { |
|
|
default: |
|
|
default: |
|
|
t = ink_push(pContext, top->executing); |
|
|
t = ink_push(pContext, top->executing); |
|
|
if(t < 0) { |
|
|
if(t < 0) { |
|
|
|
|
|
currentRoutine->runtime_error.is_set = 1; |
|
|
|
|
|
currentRoutine->runtime_error.error_message = "Literal token could not be pushed"; |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return -25; |
|
|
return -25; |
|
|
} |
|
|
} |
|
@ -873,12 +909,22 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
currentRoutine->capacity = 0; |
|
|
currentRoutine->capacity = 0; |
|
|
err = ink_lex(pContext, buffer); |
|
|
err = ink_lex(pContext, buffer); |
|
|
if(err < 0) { |
|
|
if(err < 0) { |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
executable_buffer_top = 0; |
|
|
executable_buffer_top = 0; |
|
|
err = ink_parse(pContext, executable_buffer, &executable_buffer_top); |
|
|
err = ink_parse(pContext, executable_buffer, &executable_buffer_top); |
|
|
if(err < 0) { |
|
|
if(err < 0) { |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@ -890,6 +936,11 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
main_fn[10 + integer_size] = 0; |
|
|
main_fn[10 + integer_size] = 0; |
|
|
frame.executing.value = ink_add_indigenous(pContext, main_fn, executable_buffer, executable_buffer_top); |
|
|
frame.executing.value = ink_add_indigenous(pContext, main_fn, executable_buffer, executable_buffer_top); |
|
|
if (frame.executing.value < 0) { |
|
|
if (frame.executing.value < 0) { |
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@ -898,6 +949,11 @@ int ink_compile(struct context *pContext, const char* buffer) { |
|
|
err = ink_push_fn(pContext, frame); |
|
|
err = ink_push_fn(pContext, frame); |
|
|
pContext->routines[pContext->routine_current].top = 0; |
|
|
pContext->routines[pContext->routine_current].top = 0; |
|
|
if (err < 0) { |
|
|
if (err < 0) { |
|
|
|
|
|
if(!currentRoutine->parse_error.is_set) { |
|
|
|
|
|
currentRoutine->parse_error.is_set = 1; |
|
|
|
|
|
currentRoutine->parse_error.error_message = "Could not push any executable frame: push failed"; |
|
|
|
|
|
currentRoutine->parse_error.offset = -1; |
|
|
|
|
|
} |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@ -914,7 +970,11 @@ int ink_can_run(struct context* pContext) { |
|
|
if(pContext->panic) return 0; |
|
|
if(pContext->panic) return 0; |
|
|
if(pContext->routines_top == 0) return 0; |
|
|
if(pContext->routines_top == 0) return 0; |
|
|
for(it = 0; it < pContext->routines_top; ++it) { |
|
|
for(it = 0; it < pContext->routines_top; ++it) { |
|
|
if(pContext->routines[it].panic == 0) { |
|
|
|
|
|
|
|
|
if( |
|
|
|
|
|
pContext->routines[it].panic == 0 |
|
|
|
|
|
&& !pContext->routines[it].parse_error.is_set |
|
|
|
|
|
&& !pContext->routines[it].runtime_error.is_set |
|
|
|
|
|
) { |
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -928,7 +988,12 @@ int ink_step_everyone(struct context* pContext) { |
|
|
/* Increment to next runnable routine */ |
|
|
/* Increment to next runnable routine */ |
|
|
do{ |
|
|
do{ |
|
|
++(pContext->routine_current); |
|
|
++(pContext->routine_current); |
|
|
} while(pContext->routine_current < pContext->routines_top && pContext->routines[pContext->routine_current].panic != 0); |
|
|
|
|
|
|
|
|
} while( |
|
|
|
|
|
pContext->routine_current < pContext->routines_top |
|
|
|
|
|
&& pContext->routines[pContext->routine_current].panic != 0 |
|
|
|
|
|
&& pContext->routines[pContext->routine_current].parse_error.is_set |
|
|
|
|
|
&& pContext->routines[pContext->routine_current].runtime_error.is_set |
|
|
|
|
|
); |
|
|
/* Exit condition */ |
|
|
/* Exit condition */ |
|
|
if(pContext->routine_current >= pContext->routines_top) break; |
|
|
if(pContext->routine_current >= pContext->routines_top) break; |
|
|
|
|
|
|
|
@ -1676,6 +1741,7 @@ static void new_array(struct context* ctx) { |
|
|
ary.elements = NULL; |
|
|
ary.elements = NULL; |
|
|
ary.top = 0; |
|
|
ary.top = 0; |
|
|
ary.capacity = 0; |
|
|
ary.capacity = 0; |
|
|
|
|
|
ary.flags = 0; |
|
|
e = ink_make_native(ctx, tid, &ary); |
|
|
e = ink_make_native(ctx, tid, &ary); |
|
|
ink_push(ctx, e); |
|
|
ink_push(ctx, e); |
|
|
} |
|
|
} |
|
@ -1703,26 +1769,32 @@ static void push_array_stack_delim(struct context* ctx) { |
|
|
ink_push(ctx, e); |
|
|
ink_push(ctx, e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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->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); |
|
|
|
|
|
if(renewed == NULL) { |
|
|
|
|
|
return 1; |
|
|
|
|
|
} else { |
|
|
|
|
|
ary->elements = renewed; |
|
|
|
|
|
ary->capacity = new_count; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
ary->elements[ary->top] = value; |
|
|
|
|
|
ary->top++; |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct ink_array* ary, struct elem value) { |
|
|
void array_push(struct context* ctx, struct ink_routine* currentRoutine, struct ink_array* ary, struct elem value) { |
|
|
if(ary->elements == NULL) { |
|
|
|
|
|
ary->elements = ctx->malloc(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); |
|
|
|
|
|
if(renewed == NULL) { |
|
|
|
|
|
currentRoutine->panic = -1; |
|
|
|
|
|
return; |
|
|
|
|
|
} else { |
|
|
|
|
|
ary->elements = renewed; |
|
|
|
|
|
ary->capacity = new_count; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
ary->elements[ary->top] = value; |
|
|
|
|
|
ary->top++; |
|
|
|
|
|
|
|
|
if(array_push_s(ctx, ary, value)) { |
|
|
|
|
|
currentRoutine->panic = -1; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void push_array(struct context* ctx) { |
|
|
static void push_array(struct context* ctx) { |
|
|