|
|
@ -288,199 +288,10 @@ static char* ink_itoa(struct context* _, int cpy) { |
|
|
|
return n; |
|
|
|
} |
|
|
|
|
|
|
|
static void print_stacktrace(struct context* _) { |
|
|
|
int i = 0; |
|
|
|
for(; i < _->function_stack_top; ++i) { |
|
|
|
struct elem thing = _->function_stack[i].executing; |
|
|
|
switch(thing.type) { |
|
|
|
case INK_NATIVE_FUNCTION: { |
|
|
|
char *n = _->native_words[thing.value].name; |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->putchar(10); |
|
|
|
break; |
|
|
|
} |
|
|
|
case INK_FUNCTION:{ |
|
|
|
char *n = _->native_words[thing.value].name; |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->putchar(':'); |
|
|
|
n = ink_itoa(_, _->function_stack[i].index); |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->free(n); |
|
|
|
_->putchar(10); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void add_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = a.value + b.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void dupe_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
ink_push(ctx, a); |
|
|
|
} |
|
|
|
|
|
|
|
static void drop_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
static void pluck_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
int position = ctx->top - (a.value + 1); |
|
|
|
if(position >= ctx->top || position < 0) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ink_push(ctx, ctx->stack[position]); |
|
|
|
} |
|
|
|
|
|
|
|
static void swap_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
ctx->stack[ctx->top-2] = a; |
|
|
|
ctx->stack[ctx->top-1] = b; |
|
|
|
} |
|
|
|
|
|
|
|
static void return_if(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
if(a.value) { |
|
|
|
ink_pop_fn(ctx); |
|
|
|
ink_pop_fn(ctx); |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void jump_if(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
if(a.value) { |
|
|
|
ink_pop_fn(ctx); |
|
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
ctx->function_stack[ctx->function_stack_top - 1].index += a.value - 3; |
|
|
|
ink_pop(ctx); |
|
|
|
//printf("\t*%d\n", ctx->function_stack[ctx->function_stack_top - 1].index); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void print_int(struct context* ctx) { |
|
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
ink_pop(ctx); |
|
|
|
char* n = ink_itoa(ctx, a.value); |
|
|
|
char* str = n; |
|
|
|
while (*str) { |
|
|
|
ctx->putchar(*str); |
|
|
|
++str; |
|
|
|
} |
|
|
|
ctx->free(n); |
|
|
|
} |
|
|
|
|
|
|
|
static void print_as_utf8(struct context* ctx) { |
|
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.value <= 0x7F) { |
|
|
|
ctx->putchar(a.value); |
|
|
|
} else if(a.value <= 0x7FF) { |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 192); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0xFFFF) { |
|
|
|
ctx->putchar(((a.value & 0x3F000) >> 12) | 224); |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0x10FFFF) { |
|
|
|
ctx->putchar(((a.value & 0x3C0000) >> 18) | 240); |
|
|
|
ctx->putchar(((a.value & 0x3F000) >> 12) | 128); |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef NOSTDLIB |
|
|
|
struct context* ink_make_default_context() { |
|
|
|
struct context* ctx = ink_make_context(malloc, realloc, free, putchar); |
|
|
|
ink_add_native(ctx, "trace", print_stacktrace); |
|
|
|
ink_add_native(ctx, "print_int", print_int); |
|
|
|
ink_add_native(ctx, "print_utf8", print_as_utf8); |
|
|
|
ink_add_native(ctx, "+", add_int); |
|
|
|
ink_add_native(ctx, "swap", swap_elem); |
|
|
|
ink_add_native(ctx, "dup", dupe_elem); |
|
|
|
ink_add_native(ctx, "drop", drop_elem); |
|
|
|
ink_add_native(ctx, "pluck", pluck_elem); |
|
|
|
ink_add_native(ctx, "return_if", return_if); |
|
|
|
ink_add_native(ctx, "jump_if", jump_if); |
|
|
|
ink_std_library(ctx); |
|
|
|
return ctx; |
|
|
|
} |
|
|
|
#endif |
|
|
@ -785,4 +596,263 @@ void ink_run(struct context *pContext, char* buffer) { |
|
|
|
do { |
|
|
|
out = ink_step(pContext); |
|
|
|
} while(out > 0); |
|
|
|
} |
|
|
|
|
|
|
|
/**********************************************************************************************************************/ |
|
|
|
|
|
|
|
static void print_stacktrace(struct context* _) { |
|
|
|
int i = 0; |
|
|
|
for(; i < _->function_stack_top; ++i) { |
|
|
|
struct elem thing = _->function_stack[i].executing; |
|
|
|
switch(thing.type) { |
|
|
|
case INK_NATIVE_FUNCTION: { |
|
|
|
char *n = _->native_words[thing.value].name; |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->putchar(10); |
|
|
|
break; |
|
|
|
} |
|
|
|
case INK_FUNCTION:{ |
|
|
|
char *n = _->native_words[thing.value].name; |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->putchar(':'); |
|
|
|
n = ink_itoa(_, _->function_stack[i].index); |
|
|
|
while (*n) { |
|
|
|
_->putchar(*n); |
|
|
|
++n; |
|
|
|
} |
|
|
|
_->free(n); |
|
|
|
_->putchar(10); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void add_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = a.value + b.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void sub_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = b.value - a.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void mult_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = b.value * a.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void div_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = b.value / a.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void rem_int(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ctx->stack[ctx->top-1].value = b.value % a.value; |
|
|
|
} |
|
|
|
|
|
|
|
static void dupe_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
ink_push(ctx, a); |
|
|
|
} |
|
|
|
|
|
|
|
static void drop_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
static void pluck_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
int position = ctx->top - (a.value + 1); |
|
|
|
if(position >= ctx->top || position < 0) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
ink_push(ctx, ctx->stack[position]); |
|
|
|
} |
|
|
|
|
|
|
|
static void swap_elem(struct context* ctx) { |
|
|
|
if(ctx->top < 2) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
struct elem b = ctx->stack[ctx->top-2]; |
|
|
|
ctx->stack[ctx->top-2] = a; |
|
|
|
ctx->stack[ctx->top-1] = b; |
|
|
|
} |
|
|
|
|
|
|
|
static void return_if(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
if(a.value) { |
|
|
|
ink_pop_fn(ctx); |
|
|
|
ink_pop_fn(ctx); |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void jump_if(struct context* ctx) { |
|
|
|
if(ctx->top < 1) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
if(a.value) { |
|
|
|
ink_pop_fn(ctx); |
|
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
ctx->function_stack[ctx->function_stack_top - 1].index += a.value - 3; |
|
|
|
ink_pop(ctx); |
|
|
|
//printf("\t*%d\n", ctx->function_stack[ctx->function_stack_top - 1].index); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
static void print_int(struct context* ctx) { |
|
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
ink_pop(ctx); |
|
|
|
char* n = ink_itoa(ctx, a.value); |
|
|
|
char* str = n; |
|
|
|
while (*str) { |
|
|
|
ctx->putchar(*str); |
|
|
|
++str; |
|
|
|
} |
|
|
|
ctx->free(n); |
|
|
|
} |
|
|
|
|
|
|
|
static void print_as_utf8(struct context* ctx) { |
|
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
struct elem a = ctx->stack[ctx->top-1]; |
|
|
|
if(a.value <= 0x7F) { |
|
|
|
ctx->putchar(a.value); |
|
|
|
} else if(a.value <= 0x7FF) { |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 192); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0xFFFF) { |
|
|
|
ctx->putchar(((a.value & 0x3F000) >> 12) | 224); |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else if(a.value <= 0x10FFFF) { |
|
|
|
ctx->putchar(((a.value & 0x3C0000) >> 18) | 240); |
|
|
|
ctx->putchar(((a.value & 0x3F000) >> 12) | 128); |
|
|
|
ctx->putchar(((a.value & 0xFC0) >> 6) | 128); |
|
|
|
ctx->putchar((a.value & 0x3F) | 128); |
|
|
|
} else { |
|
|
|
ctx->panic = 1; |
|
|
|
return; |
|
|
|
} |
|
|
|
ink_pop(ctx); |
|
|
|
} |
|
|
|
|
|
|
|
void ink_std_library(struct context* ctx) { |
|
|
|
ink_add_native(ctx, "trace", print_stacktrace); |
|
|
|
ink_add_native(ctx, "print_int", print_int); |
|
|
|
ink_add_native(ctx, "print_utf8", print_as_utf8); |
|
|
|
ink_add_native(ctx, "+", add_int); |
|
|
|
ink_add_native(ctx, "-", sub_int); |
|
|
|
ink_add_native(ctx, "*", mult_int); |
|
|
|
ink_add_native(ctx, "/", div_int); |
|
|
|
ink_add_native(ctx, "%", rem_int); |
|
|
|
ink_add_native(ctx, "swap", swap_elem); |
|
|
|
ink_add_native(ctx, "dup", dupe_elem); |
|
|
|
ink_add_native(ctx, "drop", drop_elem); |
|
|
|
ink_add_native(ctx, "pluck", pluck_elem); |
|
|
|
ink_add_native(ctx, "return_if", return_if); |
|
|
|
ink_add_native(ctx, "jump_if", jump_if); |
|
|
|
} |