From 5845434529c48283f2be93ebe3793fa377949d03 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 19 Apr 2017 12:56:29 -0400 Subject: [PATCH] Add readline to repl for better experience --- Makefile | 2 +- client/main.c | 29 +++++++++++----------- core/disasm.c | 3 ++- core/stl.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ core/util.c | 57 +++++++++++++++++++++++++++++++++++++++++- core/value.c | 33 +++++-------------------- core/vm.c | 23 +++++++++-------- include/gst/gst.h | 28 +++++++++++++++++++-- 8 files changed, 180 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index 858140c4..6842e0ee 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ ###################################################### ##### Set global variables for all gst Makefiles ##### ###################################################### -CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -I./include -g +CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -I./include -g -lreadline PREFIX=/usr/local GST_TARGET=client/gst GST_CORELIB=core/libgst.a diff --git a/client/main.c b/client/main.c index 98e7d076..66752b74 100644 --- a/client/main.c +++ b/client/main.c @@ -28,6 +28,10 @@ #include #include +/* Use readline support for now */ +#include +#include + /* Compile and run an ast */ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) { GstCompiler c; @@ -43,9 +47,9 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) { return 1; } /* Print disasm */ - printf("%c[31m===== Begin Disassembly =====\n", 27); - gst_dasm_function(stdout, func.data.function); - printf("===== End Disassembly =====%c[0m\n", 27); + /*printf("%c[31m===== Begin Disassembly =====\n", 27);*/ + /*gst_dasm_function(stdout, func.data.function);*/ + /*printf("===== End Disassembly =====%c[0m\n", 27);*/ /* Execute function */ if (gst_run(vm, func)) { if (vm->crash) { @@ -102,23 +106,20 @@ int debug_run(Gst *vm, FILE *in) { /* A simple repl */ int debug_repl(Gst *vm) { - char buffer[1024] = {0}; - const char *reader = buffer; + const char *buffer, *reader; GstParser p; GstValue *st; - int reset; for (;;) { /* Init parser */ gst_parser(&p, vm); - reset = 1; + buffer = reader = NULL; while (p.status != GST_PARSER_ERROR && p.status != GST_PARSER_FULL) { - if (*reader == '\0') { - if (reset) - printf(">> "); - reset = 0; - if (!fgets(buffer, sizeof(buffer), stdin)) { - break; - } + gst_parse_cstring(&p, "\n"); + if (p.status == GST_PARSER_ERROR || p.status == GST_PARSER_FULL) + break; + if (!reader || *reader == '\0') { + buffer = readline(">> "); + add_history(buffer); reader = buffer; } reader += gst_parse_cstring(&p, reader); diff --git a/core/disasm.c b/core/disasm.c index 623d7239..144d490e 100644 --- a/core/disasm.c +++ b/core/disasm.c @@ -66,7 +66,8 @@ static uint32_t dasm_varg_op(FILE * out, const uint16_t * current, dasm_print_slot(out, current[i + 1]); } argCount = current[extra + 1]; - fprintf(out, ": "); /* Argument separator */ + if (extra) + fprintf(out, ": "); /* Argument separator */ for (i = 0; i < argCount; ++i) { dasm_print_slot(out, current[i + extra + 2]); } diff --git a/core/stl.c b/core/stl.c index e36f6015..1f7a6299 100644 --- a/core/stl.c +++ b/core/stl.c @@ -168,6 +168,68 @@ int gst_stl_select(Gst *vm) { gst_c_return(vm, gst_arg(vm, n + 1)); } +/* Get a slice of a sequence */ +int gst_stl_slice(Gst *vm) { + uint32_t count = gst_count_args(vm); + int32_t from, to; + GstValue x; + const GstValue *data; + uint32_t length; + uint32_t newlength; + GstNumber num; + + /* Check args */ + if (count < 1) + gst_c_throwc(vm, "slice takes at least one argument"); + x = gst_arg(vm, 0); + + /* Get data */ + if (x.type == GST_TUPLE) { + data = x.data.st; + length = gst_tuple_length(x.data.st); + } else if (x.type == GST_ARRAY) { + data = x.data.array->data; + length = x.data.array->count; + } else { + gst_c_throwc(vm, "expected array or tuple"); + } + + /* Get from index */ + if (count < 2) { + from = 0; + } else { + if (!gst_check_number(vm, 1, &num)) + gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP); + from = gst_to_index(num, length); + } + + /* Get to index */ + if (count < 3) { + to = length; + } else { + if (!gst_check_number(vm, 2, &num)) + gst_c_throwc(vm, GST_EXPECTED_NUMBER_OP); + to = gst_to_endrange(num, length); + } + + /* Check from bad bounds */ + if (from < 0 || to < 0) + gst_c_throwc(vm, "index out of bounds"); + + /* Build slice */ + newlength = to - from; + if (x.type == GST_TUPLE) { + GstValue *tup = gst_tuple_begin(vm, newlength); + gst_memcpy(tup, data + from, newlength * sizeof(GstValue)); + gst_c_return(vm, gst_wrap_tuple(gst_tuple_end(vm, tup))); + } else { + GstArray *arr = gst_array(vm, newlength); + arr->count = newlength; + gst_memcpy(arr->data, data + from, newlength * sizeof(GstValue)); + gst_c_return(vm, gst_wrap_array(arr)); + } +} + /* Get type of object */ int gst_stl_type(Gst *vm) { GstValue x; @@ -446,6 +508,7 @@ static const GstModuleItem const std_module[] = { {"length", gst_stl_length}, {"type", gst_stl_type}, {"select", gst_stl_select}, + {"slice", gst_stl_slice}, {"array", gst_stl_array}, {"tuple", gst_stl_tuple}, {"object", gst_stl_object}, diff --git a/core/util.c b/core/util.c index 545e8462..6e0e9b2b 100644 --- a/core/util.c +++ b/core/util.c @@ -31,13 +31,25 @@ GstValue gst_wrap_nil() { return y; } +int gst_check_nil(Gst *vm, uint32_t i) { + GstValue a = gst_arg(vm, i); + return a.type == GST_NIL; +} + #define GST_WRAP_DEFINE(NAME, TYPE, GTYPE, UM)\ GstValue gst_wrap_##NAME(TYPE x) {\ GstValue y;\ y.type = GTYPE;\ y.data.UM = x;\ return y;\ -} +}\ +\ +int gst_check_##NAME(Gst *vm, uint32_t i, TYPE (*out)) {\ + GstValue a = gst_arg(vm, i);\ + if (a.type != GTYPE) return 0;\ + *out = a.data.UM;\ + return 1;\ +}\ GST_WRAP_DEFINE(number, GstNumber, GST_NUMBER, number) GST_WRAP_DEFINE(boolean, int, GST_BOOLEAN, boolean) @@ -109,3 +121,46 @@ GstValue gst_register_get(Gst *vm, const char *name) { return gst_wrap_nil(); return gst_object_get(vm->registry, gst_string_cv(vm, name)); } + +/****/ +/* Misc */ +/****/ + +/* Allow negative indexing to get from end of array like structure */ +/* This probably isn't very fast - look at Lua conversion function. + * I would like to keep this standard C for as long as possible, though. */ +int32_t gst_to_index(GstNumber raw, int64_t len) { + int32_t toInt = raw; + if ((GstNumber) toInt == raw) { + /* We were able to convert */ + if (toInt < 0 && len > 0) { + /* Index from end */ + if (toInt < -len) return -1; + return len + toInt; + } else { + /* Normal indexing */ + if (toInt >= len) return -1; + return toInt; + } + } else { + return -1; + } +} + +int32_t gst_to_endrange(GstNumber raw, int64_t len) { + int32_t toInt = raw; + if ((GstNumber) toInt == raw) { + /* We were able to convert */ + if (toInt < 0 && len > 0) { + /* Index from end */ + if (toInt < -len - 1) return -1; + return len + toInt + 1; + } else { + /* Normal indexing */ + if (toInt >= len) return -1; + return toInt; + } + } else { + return -1; + } +} diff --git a/core/value.c b/core/value.c index 24961f99..a6d58226 100644 --- a/core/value.c +++ b/core/value.c @@ -236,27 +236,6 @@ int gst_compare(GstValue x, GstValue y) { return 1; } -/* Allow negative indexing to get from end of array like structure */ -/* This probably isn't very fast - look at Lua conversion function. - * I would like to keep this standard C for as long as possible, though. */ -static int32_t to_index(GstNumber raw, int64_t len) { - int32_t toInt = raw; - if ((GstNumber) toInt == raw) { - /* We were able to convert */ - if (toInt < 0 && len > 0) { - /* Index from end */ - if (toInt < -len) return -1; - return len + toInt; - } else { - /* Normal indexing */ - if (toInt >= len) return -1; - return toInt; - } - } else { - return -1; - } -} - /* Convert a number into a byte. */ static uint8_t to_byte(GstNumber raw) { if (raw > 255) return 255; @@ -273,26 +252,26 @@ const char *gst_get(GstValue ds, GstValue key, GstValue *out) { switch (ds.type) { case GST_ARRAY: if (key.type != GST_NUMBER) return "expected numeric key"; - index = to_index(key.data.number, ds.data.array->count); + index = gst_to_index(key.data.number, ds.data.array->count); if (index == -1) return "invalid array access"; ret = ds.data.array->data[index]; break; case GST_TUPLE: if (key.type != GST_NUMBER) return "expected numeric key"; - index = to_index(key.data.number, gst_tuple_length(ds.data.tuple)); + index = gst_to_index(key.data.number, gst_tuple_length(ds.data.tuple)); if (index < 0) return "invalid tuple access"; ret = ds.data.tuple[index]; break; case GST_BYTEBUFFER: if (key.type != GST_NUMBER) return "expected numeric key"; - index = to_index(key.data.number, ds.data.buffer->count); + index = gst_to_index(key.data.number, ds.data.buffer->count); if (index == -1) return "invalid buffer access"; ret.type = GST_NUMBER; ret.data.number = ds.data.buffer->data[index]; break; case GST_STRING: if (key.type != GST_NUMBER) return "expected numeric key"; - index = to_index(key.data.number, gst_string_length(ds.data.string)); + index = gst_to_index(key.data.number, gst_string_length(ds.data.string)); if (index == -1) return "invalid string access"; ret.type = GST_NUMBER; ret.data.number = ds.data.string[index]; @@ -317,14 +296,14 @@ const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) { switch (ds.type) { case GST_ARRAY: if (key.type != GST_NUMBER) return "expected numeric key"; - index = to_index(key.data.number, ds.data.array->count); + index = gst_to_index(key.data.number, ds.data.array->count); if (index == -1) return "invalid array access"; ds.data.array->data[index] = value; break; case GST_BYTEBUFFER: if (key.type != GST_NUMBER) return "expected numeric key"; if (value.type != GST_NUMBER) return "expected numeric value"; - index = to_index(key.data.number, ds.data.buffer->count); + index = gst_to_index(key.data.number, ds.data.buffer->count); if (index == -1) return "invalid buffer access"; ds.data.buffer->data[index] = to_byte(value.data.number); break; diff --git a/core/vm.c b/core/vm.c index 147086d1..b76941a2 100644 --- a/core/vm.c +++ b/core/vm.c @@ -310,18 +310,6 @@ int gst_continue(Gst *vm) { } break; - case GST_OP_YLD: /* Yield to new thread */ - temp = stack[pc[1]]; - v1 = stack[pc[2]]; - gst_assert(vm, v1.type == GST_THREAD, "expected thread"); - gst_assert(vm, v1.data.thread->status != GST_THREAD_DEAD, "cannot rejoin dead thread"); - gst_frame_pc(stack) = pc + 3; - vm->thread = v1.data.thread; - vm->thread->status = GST_THREAD_ALIVE; - stack = vm->thread->data + vm->thread->count; - pc = gst_frame_pc(stack); - continue; - /* Faster implementations of standard functions * These opcodes are nto strictlyre required and can * be reimplemented with stanard library functions */ @@ -444,6 +432,17 @@ int gst_continue(Gst *vm) { } break; + case GST_OP_YLD: /* Yield to new thread */ + temp = stack[pc[1]]; + v1 = stack[pc[2]]; + gst_assert(vm, v1.type == GST_THREAD, "expected thread"); + gst_assert(vm, v1.data.thread->status != GST_THREAD_DEAD, "cannot rejoin dead thread"); + gst_frame_pc(stack) = pc + 3; + vm->thread = v1.data.thread; + vm->thread->status = GST_THREAD_ALIVE; + stack = vm->thread->data + vm->thread->count; + pc = gst_frame_pc(stack); + continue; /* Handle errors from c functions and vm opcodes */ vm_error: diff --git a/include/gst/gst.h b/include/gst/gst.h index 4bbad92a..51fb1a07 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -503,9 +503,9 @@ GstValue gst_arg(Gst *vm, uint16_t index); void gst_set_arg(Gst *vm, uint16_t index, GstValue x); uint16_t gst_count_args(Gst *vm); -/***/ +/****/ /* C Api */ -/***/ +/****/ GstValue gst_cmodule_object(Gst *vm, const GstModuleItem *mod); GstValue gst_cmodule_struct(Gst *vm, const GstModuleItem *mod); @@ -531,4 +531,28 @@ GstValue gst_wrap_userdata(void *x); GstValue gst_wrap_funcenv(GstFuncEnv *x); GstValue gst_wrap_funcdef(GstFuncDef *x); +/* Check data from arguments */ +int gst_check_nil(Gst *vm, uint32_t i); +int gst_check_number(Gst *vm, uint32_t i, GstNumber (*x)); +int gst_check_boolean(Gst *vm, uint32_t i, int (*x)); +int gst_check_string(Gst *vm, uint32_t i, const uint8_t *(*x)); +int gst_check_array(Gst *vm, uint32_t i, GstArray *(*x)); +int gst_check_tuple(Gst *vm, uint32_t i, const GstValue *(*x)); +int gst_check_struct(Gst *vm, uint32_t i, const GstValue *(*x)); +int gst_check_thread(Gst *vm, uint32_t i, GstThread *(*x)); +int gst_check_buffer(Gst *vm, uint32_t i, GstBuffer *(*x)); +int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x)); +int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x)); +int gst_check_object(Gst *vm, uint32_t i, GstObject *(*x)); +int gst_check_userdata(Gst *vm, uint32_t i, void *(*x)); +int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x)); +int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x)); + +/****/ +/* Misc */ +/****/ + +int32_t gst_to_index(GstNumber raw, int64_t len); +int32_t gst_to_endrange(GstNumber raw, int64_t len); + #endif // GST_H_defined