From d7610138a9dee6526a0dfd195b745cec15c01b0e Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Thu, 15 Jan 2026 06:22:10 +0100 Subject: [PATCH] Several fixes: - Better (more) error handling - CMakeLists clean-up - added memset to the set of standard function I needed to ~~steal~~ borrow from OpenBSD --- CMakeLists.txt | 12 ++- README.md | 1 - include/ink.h | 8 +- lib.c | 244 +++++++++++++++++++++++++++++++++++++------------ sh.c | 106 +-------------------- 5 files changed, 198 insertions(+), 173 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 996bc83..bdd0d7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,10 @@ include(CTest) set(CMAKE_C_STANDARD 90) -add_library(ink lib.c include/ink.h) +add_library(ink-static lib.c include/ink.h) +target_include_directories(ink-static PUBLIC include) +add_library(ink SHARED lib.c include/ink.h) +target_include_directories(ink PUBLIC include) # Uncomment to disable the redundant arithmetic # add_definitions(-DNOEXTRAARITHMETIC) @@ -25,19 +28,18 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE) add_executable(ink_exe main.c) -target_link_libraries(ink_exe PUBLIC ink) -target_include_directories(ink PUBLIC include) +target_link_libraries(ink_exe PUBLIC ink-static) add_executable(inksh sh.c) target_compile_definitions(inksh PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") -target_link_libraries(inksh PUBLIC ink) +target_link_libraries(inksh PUBLIC ink-static) # Functional tests function(add_success_compiled_test cfile success_regex) add_executable(${cfile} test/${cfile}.c) - target_link_libraries(${cfile} PUBLIC ink) + target_link_libraries(${cfile} PUBLIC ink-static) add_test(NAME ${cfile} COMMAND ${cfile}) set_property (TEST ${cfile} PROPERTY PASS_REGULAR_EXPRESSION "${success_regex}") diff --git a/README.md b/README.md index d97a183..d2110d7 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,6 @@ It is possible to segregate unsafe allocations (allocations that should be hidde - Shell can import files (requires waiting for a routine in a routine) - Waiting for another routine - Executing other routines -- Move shell words to base implementation *iff* they do not have any external dependency (e.g.: `version`) - Less context panics, more routine panics ## Examples diff --git a/include/ink.h b/include/ink.h index dd44e62..f2ec5d5 100644 --- a/include/ink.h +++ b/include/ink.h @@ -1,6 +1,6 @@ #pragma once -#include "stddef.h" -#include "stdint.h" +#include +#include /** @@ -290,7 +290,7 @@ int ink_compile(struct context *pContext, const char *buffer); /** * Includes the standard library in the specified context * @param ctx The context - * @return 0 + * @return 0 on success */ int ink_std_library(struct context *ctx); @@ -312,7 +312,7 @@ typedef struct ink_collection_list (*gc_fn)(struct context*,void*); /** * Declares a new type that can be stored within the interpreter * @param ctx The context in which to add the file - * @param type_name The name of the type we want to add + * @param type_name The name of the type we want to add, IT WILL **NOT** BE COPIED. This string is expected to remain valid and unaltered for the runtime of the program * @param size The size in bytes of the type to add, size of 0 mean no size, in which case the type is adjacent to C int, negative size means that the memory is not managed by the interpreter. * @param collect A "destructor" function for the data * @param gc A function that returns a list (allocated with the `inner_malloc`) of all the elements this element holds references to diff --git a/lib.c b/lib.c index e7e879b..b9e9913 100644 --- a/lib.c +++ b/lib.c @@ -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 = (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; } diff --git a/sh.c b/sh.c index 1a92085..cdef896 100644 --- a/sh.c +++ b/sh.c @@ -12,9 +12,7 @@ #define GIT_COMMIT_HASH "?" #endif -int get_type_by_name(struct context* ctx, const char* name); - -static void print_string(struct context* ctx, const struct elem string) { +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) { @@ -40,96 +38,7 @@ static void print_string(struct context* ctx, const struct elem string) { } } -static void list_words(struct context* ctx) { - struct native_fn* nit; - struct fn* dit; - int i; - 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; - unsigned char* name; - int it; - 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) { - 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; - unsigned char* name; - int it; - int found = 0; - 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); -} +int get_type_by_name(struct context* ctx, const char* name); static void print_releasever(struct context* ctx) { const char * commit = GIT_COMMIT_HASH; @@ -148,25 +57,14 @@ static void read_stdin(struct context* ctx) { ink_push(ctx, e); } -static void static_EOF(struct context* ctx) { - struct elem e; - e.type = INK_INTEGER; - e.value = EOF; - ink_push(ctx, e); -} - int main(int argc, char** argv) { char read_buffer[INK_SH_READ_BUFF]; struct context* ctx; char** end_argv; int interactive = 1; ctx = ink_make_default_context(); - ink_add_native(ctx, "words?", list_words); - ink_add_native(ctx, "words!", resolve_word); - ink_add_native(ctx, "words.call", call_word); ink_add_native(ctx, "version", print_releasever); ink_add_native(ctx, "read-stdin", read_stdin); - ink_add_native(ctx, "EOF", static_EOF); end_argv = argv + argc; size_t cnt; int no_exit = 1;