mirror of
https://github.com/janet-lang/janet
synced 2024-12-25 07:50:27 +00:00
Add readline to repl for better experience
This commit is contained in:
parent
fb3abf5a31
commit
5845434529
2
Makefile
2
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
|
||||
|
@ -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)) {
|
||||
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);
|
||||
|
@ -66,6 +66,7 @@ static uint32_t dasm_varg_op(FILE * out, const uint16_t * current,
|
||||
dasm_print_slot(out, current[i + 1]);
|
||||
}
|
||||
argCount = current[extra + 1];
|
||||
if (extra)
|
||||
fprintf(out, ": "); /* Argument separator */
|
||||
for (i = 0; i < argCount; ++i) {
|
||||
dasm_print_slot(out, current[i + extra + 2]);
|
||||
|
63
core/stl.c
63
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},
|
||||
|
57
core/util.c
57
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;
|
||||
}
|
||||
}
|
||||
|
33
core/value.c
33
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;
|
||||
|
23
core/vm.c
23
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:
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user