Browse Source

added better error feedback and detection

main
Ludovic 'Archivist' Lagouardette 2 months ago
parent
commit
f5e6d3477d
3 changed files with 116 additions and 28 deletions
  1. +1
    -1
      CMakeLists.txt
  2. +17
    -1
      include/ink.h
  3. +98
    -26
      lib.c

+ 1
- 1
CMakeLists.txt View File

@ -11,7 +11,7 @@ add_library(ink lib.c include/ink.h)
# Uncomment to disable array types # Uncomment to disable array types
# add_definitions(-DNOARRAYLIB) # add_definitions(-DNOARRAYLIB)
# Uncomment to disable string literals
# Uncomment to disable string literal
# add_definitions(-DNOSTRINGLITERALS) # add_definitions(-DNOSTRINGLITERALS)
# Ensures the interpreter doesn't use the standard C library functions # Ensures the interpreter doesn't use the standard C library functions

+ 17
- 1
include/ink.h View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "stddef.h" #include "stddef.h"
#include "stdint.h"
/** /**
@ -66,12 +67,26 @@ struct native_fn {
void (*value)(struct context *); void (*value)(struct context *);
}; };
struct parse_error {
int is_set;
const char* error_message;
size_t offset;
};
struct runtime_error {
int is_set;
const char* error_message;
};
/** /**
* Represents the narrow execution context of a single thread of execution within ink. * Represents the narrow execution context of a single thread of execution within ink.
*/ */
struct ink_routine { struct ink_routine {
int panic; int panic;
struct parse_error parse_error;
struct runtime_error runtime_error;
struct elem *stack; struct elem *stack;
int capacity; int capacity;
int top; int top;
@ -338,6 +353,7 @@ struct ink_array {
int top; int top;
int capacity; int capacity;
struct elem* elements; struct elem* elements;
uint16_t flags;
}; };
/** /**

+ 98
- 26
lib.c View File

@ -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) {

Loading…
Cancel
Save