Просмотр исходного кода

added better error feedback and detection

main
Ludovic 'Archivist' Lagouardette 2 месяцев назад
Родитель
Сommit
f5e6d3477d
3 измененных файлов: 116 добавлений и 28 удалений
  1. +1
    -1
      CMakeLists.txt
  2. +17
    -1
      include/ink.h
  3. +98
    -26
      lib.c

+ 1
- 1
CMakeLists.txt Просмотреть файл

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

+ 17
- 1
include/ink.h Просмотреть файл

@ -1,5 +1,6 @@
#pragma once
#include "stddef.h"
#include "stdint.h"
/**
@ -66,12 +67,26 @@ struct native_fn {
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.
*/
struct ink_routine {
int panic;
struct parse_error parse_error;
struct runtime_error runtime_error;
struct elem *stack;
int capacity;
int top;
@ -338,6 +353,7 @@ struct ink_array {
int top;
int capacity;
struct elem* elements;
uint16_t flags;
};
/**

+ 98
- 26
lib.c Просмотреть файл

@ -21,6 +21,8 @@
#define _KEYWORD_INK_END "end"
#define _KEYWORD_INK_RETURN "return"
#define INK_ARRAY_FLAG_PROTECTED 1
#define min(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->function_stack = NULL;
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) {
int new_count;
@ -604,7 +608,11 @@ int ink_make_routine(struct context* ctx) {
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;
}
@ -617,12 +625,9 @@ int ink_make_routine(struct context* ctx) {
if(it->panic == INK_ROUTINE_CAN_REUSE) {
int idx;
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;
idx = it - ctx->routines;
if(idx >= ctx->routines_top) {
ctx->routines_top = idx + 1;
@ -630,6 +635,7 @@ int ink_make_routine(struct context* ctx) {
return idx;
}
}
/* FIXME: Maybe we need to abort here, this seems like quite an unsteady state */
return -758;
}
@ -691,7 +697,14 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i
function_name = -1;
goto next_token;
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:
currentRoutine->parse_error.is_set = 1;
currentRoutine->parse_error.error_message = "Found end of function unexpectedly";
currentRoutine->parse_error.offset= i;
return -26;
default:
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:
if(current.type == INK_DO_KW) {
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;
@ -709,9 +725,15 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i
}
}
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;
}
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;
}
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(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) {
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;
break;
}
@ -779,6 +804,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i
next_token: i=i;
}
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 0;
@ -812,6 +840,8 @@ int ink_step(struct context *pContext) {
} else {
top->index++;
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;
}
@ -820,7 +850,9 @@ int ink_step(struct context *pContext) {
break;
case INK_FUNCTION:
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;
}
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);
if(t < 0) {
pContext->panic = 1;
currentRoutine->runtime_error.is_set = 1;
currentRoutine->runtime_error.error_message = "Instruction pointer underflow";
return -11;
}
top->index++;
@ -844,6 +878,8 @@ int ink_step(struct context *pContext) {
default:
t = ink_push(pContext, top->executing);
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;
}
@ -873,12 +909,22 @@ int ink_compile(struct context *pContext, const char* buffer) {
currentRoutine->capacity = 0;
err = ink_lex(pContext, buffer);
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;
return -1;
}
executable_buffer_top = 0;
err = ink_parse(pContext, executable_buffer, &executable_buffer_top);
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;
return -1;
}
@ -890,6 +936,11 @@ 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) {
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;
return -1;
}
@ -898,6 +949,11 @@ int ink_compile(struct context *pContext, const char* buffer) {
err = ink_push_fn(pContext, frame);
pContext->routines[pContext->routine_current].top = 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;
return -1;
}
@ -914,7 +970,11 @@ int ink_can_run(struct context* pContext) {
if(pContext->panic) return 0;
if(pContext->routines_top == 0) return 0;
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;
}
}
@ -928,7 +988,12 @@ int ink_step_everyone(struct context* pContext) {
/* Increment to next runnable routine */
do{
++(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 */
if(pContext->routine_current >= pContext->routines_top) break;
@ -1676,6 +1741,7 @@ static void new_array(struct context* ctx) {
ary.elements = NULL;
ary.top = 0;
ary.capacity = 0;
ary.flags = 0;
e = ink_make_native(ctx, tid, &ary);
ink_push(ctx, e);
}
@ -1703,26 +1769,32 @@ static void push_array_stack_delim(struct context* ctx) {
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) {
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) {

Загрузка…
Отмена
Сохранить