Add readline to repl for better experience

This commit is contained in:
Calvin Rose 2017-04-19 12:56:29 -04:00
parent fb3abf5a31
commit 5845434529
8 changed files with 180 additions and 58 deletions

View File

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

View File

@ -28,6 +28,10 @@
#include <gst/stl.h>
#include <gst/disasm.h>
/* Use readline support for now */
#include <readline/readline.h>
#include <readline/history.h>
/* 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);

View File

@ -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]);
}

View File

@ -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},

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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:

View File

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