mirror of
https://github.com/janet-lang/janet
synced 2024-12-29 01:40:26 +00:00
Make coloring changes to the repl
This commit is contained in:
parent
bfadf6ff12
commit
0cf278994d
@ -30,6 +30,12 @@ static int client_strequal(const char *a, const char *b) {
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static int client_strequal_witharg(const char *a, const char *b) {
|
||||
while (*b)
|
||||
if (*a++ != *b++) return 0;
|
||||
return *a == '=';
|
||||
}
|
||||
|
||||
#define GST_CLIENT_HELP 1
|
||||
#define GST_CLIENT_VERBOSE 2
|
||||
#define GST_CLIENT_VERSION 4
|
||||
@ -37,6 +43,14 @@ static int client_strequal(const char *a, const char *b) {
|
||||
#define GST_CLIENT_NOCOLOR 16
|
||||
#define GST_CLIENT_UNKNOWN 32
|
||||
|
||||
static void printf_flags(int64_t flags, const char *col, const char *fmt, const char *arg) {
|
||||
if (!(flags & GST_CLIENT_NOCOLOR))
|
||||
printf("\x1B[%sm", col);
|
||||
printf(fmt, arg);
|
||||
if (!(flags & GST_CLIENT_NOCOLOR))
|
||||
printf("\x1B[0m");
|
||||
}
|
||||
|
||||
/* Simple read line functionality */
|
||||
static char *gst_getline() {
|
||||
char *line = malloc(100);
|
||||
@ -68,7 +82,7 @@ static char *gst_getline() {
|
||||
}
|
||||
|
||||
/* Compile and run an ast */
|
||||
static int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) {
|
||||
static int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last, int64_t flags) {
|
||||
GstCompiler c;
|
||||
GstValue func;
|
||||
/* Try to compile generated AST */
|
||||
@ -77,15 +91,15 @@ static int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) {
|
||||
func = gst_wrap_function(gst_compiler_compile(&c, ast));
|
||||
/* Check for compilation errors */
|
||||
if (c.error.type != GST_NIL) {
|
||||
printf("Compiler error: %s\n", (const char *)gst_to_string(vm, c.error));
|
||||
printf_flags(flags, "31", "compiler error: %s\n", (const char *)gst_to_string(vm, c.error));
|
||||
return 1;
|
||||
}
|
||||
/* Execute function */
|
||||
if (gst_run(vm, func)) {
|
||||
if (vm->crash) {
|
||||
printf("VM crash: %s\n", vm->crash);
|
||||
printf_flags(flags, "31", "vm crash: %s\n", vm->crash);
|
||||
} else {
|
||||
printf("VM error: %s\n", (const char *)gst_to_string(vm, vm->ret));
|
||||
printf_flags(flags, "31", "vm error: %s\n", (const char *)gst_to_string(vm, vm->ret));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -93,7 +107,7 @@ static int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) {
|
||||
}
|
||||
|
||||
/* Parse a file and execute it */
|
||||
static int debug_run(Gst *vm, FILE *in) {
|
||||
static int debug_run(Gst *vm, FILE *in, int64_t flags) {
|
||||
char buffer[2048] = {0};
|
||||
const char *reader = buffer;
|
||||
GstParser p;
|
||||
@ -105,7 +119,7 @@ static int debug_run(Gst *vm, FILE *in) {
|
||||
if (!fgets(buffer, sizeof(buffer), in)) {
|
||||
/* Check that parser is complete */
|
||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
||||
printf("Unexpected end of source\n");
|
||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||
return 1;
|
||||
}
|
||||
/* Otherwise we finished the file with no problems*/
|
||||
@ -117,15 +131,15 @@ static int debug_run(Gst *vm, FILE *in) {
|
||||
}
|
||||
/* Check if file read in correctly */
|
||||
if (p.error) {
|
||||
printf("Parse error: %s\n", p.error);
|
||||
printf_flags(flags, "31", "parse error: %s\n", p.error);
|
||||
break;
|
||||
}
|
||||
/* Check that parser is complete */
|
||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
||||
printf("Unexpected end of source\n");
|
||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||
break;
|
||||
}
|
||||
if (debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret)) {
|
||||
if (debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret, flags)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -144,11 +158,7 @@ static int debug_repl(Gst *vm, uint64_t flags) {
|
||||
if (p.status == GST_PARSER_ERROR || p.status == GST_PARSER_FULL)
|
||||
break;
|
||||
if (!reader || *reader == '\0') {
|
||||
if (flags & GST_CLIENT_NOCOLOR) {
|
||||
printf(">>> ");
|
||||
} else {
|
||||
printf("\x1B[33m>>>\x1B[0m ");
|
||||
}
|
||||
printf_flags(flags, "33", "> %s", "");
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
buffer = gst_getline();
|
||||
@ -160,21 +170,17 @@ static int debug_repl(Gst *vm, uint64_t flags) {
|
||||
}
|
||||
/* Check if file read in correctly */
|
||||
if (p.error) {
|
||||
printf("Parse error: %s\n", p.error);
|
||||
printf_flags(flags, "31", "parse error: %s\n", p.error);
|
||||
buffer = reader = NULL;
|
||||
continue;
|
||||
}
|
||||
/* Check that parser is complete */
|
||||
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
|
||||
printf("Unexpected end of source\n");
|
||||
printf_flags(flags, "31", "parse error: unexpected end of source%s\n", "");
|
||||
continue;
|
||||
}
|
||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret)) {
|
||||
if (flags & GST_CLIENT_NOCOLOR) {
|
||||
printf("%s\n", gst_description(vm, vm->ret));
|
||||
} else {
|
||||
printf("\x1B[36m%s\x1B[0m\n", gst_description(vm, vm->ret));
|
||||
}
|
||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret, flags)) {
|
||||
printf_flags(flags, "36", "%s\n", (const char *) gst_description(vm, vm->ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,6 +190,7 @@ int main(int argc, const char **argv) {
|
||||
int status = -1;
|
||||
int i;
|
||||
int fileRead = 0;
|
||||
uint32_t memoryInterval = 4096;
|
||||
uint64_t flags = 0;
|
||||
|
||||
/* Read the arguments. Ignore files. */
|
||||
@ -203,6 +210,20 @@ int main(int argc, const char **argv) {
|
||||
flags |= GST_CLIENT_REPL;
|
||||
} else if (client_strequal(arg + 2, "nocolor")) {
|
||||
flags |= GST_CLIENT_NOCOLOR;
|
||||
} else if (client_strequal_witharg(arg + 2, "memchunk")) {
|
||||
int64_t val = memoryInterval;
|
||||
const uint8_t *end = (const uint8_t *)(arg + 2);
|
||||
while (*end) ++end;
|
||||
int status = gst_read_integer((const uint8_t *)arg + 11, end, &val);
|
||||
if (status) {
|
||||
if (val > 0xFFFFFFFF) {
|
||||
memoryInterval = 0xFFFFFFFF;
|
||||
} else if (val < 0) {
|
||||
memoryInterval = 0;
|
||||
} else {
|
||||
memoryInterval = val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags |= GST_CLIENT_UNKNOWN;
|
||||
}
|
||||
@ -240,11 +261,14 @@ int main(int argc, const char **argv) {
|
||||
printf( "Usage:\n"
|
||||
"%s -opts --fullopt1 --fullopt2 file1 file2...\n"
|
||||
"\n"
|
||||
" -h --help : Shows this information.\n"
|
||||
" -V --verbose : Show more output.\n"
|
||||
" -r --repl : Launch a repl after all files are processed.\n"
|
||||
" -c --nocolor : Don't use VT100 color codes in the repl.\n"
|
||||
" -v --version : Print the version number and exit.\n\n",
|
||||
" -h --help : Shows this information.\n"
|
||||
" -V --verbose : Show more output.\n"
|
||||
" -r --repl : Launch a repl after all files are processed.\n"
|
||||
" -c --nocolor : Don't use VT100 color codes in the repl.\n"
|
||||
" -v --version : Print the version number and exit.\n"
|
||||
" --memchunk=[int] : Set the amount of memory to allocate before\n"
|
||||
" forcing a collection in bytes. Max is 2^32-1,\n"
|
||||
" min is 0.\n\n",
|
||||
argv[0]);
|
||||
return 0;
|
||||
}
|
||||
@ -255,6 +279,7 @@ int main(int argc, const char **argv) {
|
||||
|
||||
/* Set up VM */
|
||||
gst_init(&vm);
|
||||
vm.memoryInterval = memoryInterval;
|
||||
gst_stl_load(&vm);
|
||||
|
||||
/* Read the arguments. Only process files. */
|
||||
@ -264,7 +289,7 @@ int main(int argc, const char **argv) {
|
||||
FILE *f;
|
||||
f = fopen(arg, "rb");
|
||||
fileRead = 1;
|
||||
status = debug_run(&vm, f);
|
||||
status = debug_run(&vm, f, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
86
core/parse.c
86
core/parse.c
@ -22,7 +22,7 @@
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static const char UNEXPECTED_CLOSING_DELIM[] = "Unexpected closing delimiter";
|
||||
static const char UNEXPECTED_CLOSING_DELIM[] = "unexpected closing delimiter";
|
||||
|
||||
/* Handle error in parsing */
|
||||
#define p_error(p, e) ((p)->error = (e), (p)->status = GST_PARSER_ERROR)
|
||||
@ -125,86 +125,6 @@ static int is_symbol_char(uint8_t c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get an integer power of 10 */
|
||||
static double exp10(int power) {
|
||||
if (power == 0) return 1;
|
||||
if (power > 0) {
|
||||
double result = 10;
|
||||
int currentPower = 1;
|
||||
while (currentPower * 2 <= power) {
|
||||
result = result * result;
|
||||
currentPower *= 2;
|
||||
}
|
||||
return result * exp10(power - currentPower);
|
||||
} else {
|
||||
return 1 / exp10(-power);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a real from a string. Returns if successfuly
|
||||
* parsed a real from the enitre input string.
|
||||
* If returned 1, output is int ret.*/
|
||||
static int read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
|
||||
int sign = 1, x = 0;
|
||||
double accum = 0, exp = 1, place = 1;
|
||||
/* Check the sign */
|
||||
if (*string == '-') {
|
||||
sign = -1;
|
||||
++string;
|
||||
} else if (*string == '+') {
|
||||
++string;
|
||||
}
|
||||
if (string >= end) return 0;
|
||||
while (string < end) {
|
||||
if (*string == '.' && !forceInt) {
|
||||
place = 0.1;
|
||||
} else if (!forceInt && (*string == 'e' || *string == 'E')) {
|
||||
/* Read the exponent */
|
||||
++string;
|
||||
if (string >= end) return 0;
|
||||
if (!read_real(string, end, &exp, 1))
|
||||
return 0;
|
||||
exp = exp10(exp);
|
||||
break;
|
||||
} else {
|
||||
x = *string;
|
||||
if (x < '0' || x > '9') return 0;
|
||||
x -= '0';
|
||||
if (place < 1) {
|
||||
accum += x * place;
|
||||
place *= 0.1;
|
||||
} else {
|
||||
accum *= 10;
|
||||
accum += x;
|
||||
}
|
||||
}
|
||||
++string;
|
||||
}
|
||||
*ret = accum * sign * exp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
|
||||
int sign = 1, x = 0;
|
||||
int64_t accum = 0;
|
||||
if (*string == '-') {
|
||||
sign = -1;
|
||||
++string;
|
||||
} else if (*string == '+') {
|
||||
++string;
|
||||
}
|
||||
if (string >= end) return 0;
|
||||
while (string < end) {
|
||||
x = *string;
|
||||
if (x < '0' || x > '9') return 0;
|
||||
x -= '0';
|
||||
accum = accum * 10 + x;
|
||||
++string;
|
||||
}
|
||||
*ret = accum * sign;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Checks if a string slice is equal to a string constant */
|
||||
static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) {
|
||||
while (*ref && start < end) {
|
||||
@ -222,10 +142,10 @@ static GstValue build_token(GstParser *p, GstBuffer *buf) {
|
||||
GstInteger integer;
|
||||
uint8_t *data = buf->data;
|
||||
uint8_t *back = data + buf->count;
|
||||
if (read_integer(data, back, &integer)) {
|
||||
if (gst_read_integer(data, back, &integer)) {
|
||||
x.type = GST_INTEGER;
|
||||
x.data.integer = integer;
|
||||
} else if (read_real(data, back, &real, 0)) {
|
||||
} else if (gst_read_real(data, back, &real, 0)) {
|
||||
x.type = GST_REAL;
|
||||
x.data.real = real;
|
||||
} else if (check_str_const("nil", data, back)) {
|
||||
|
89
core/util.c
89
core/util.c
@ -85,6 +85,95 @@ void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type) {
|
||||
return x.data.pointer;
|
||||
}
|
||||
|
||||
/****/
|
||||
/* Parsing utils */
|
||||
/****/
|
||||
|
||||
|
||||
/* Get an integer power of 10 */
|
||||
static double exp10(int power) {
|
||||
if (power == 0) return 1;
|
||||
if (power > 0) {
|
||||
double result = 10;
|
||||
int currentPower = 1;
|
||||
while (currentPower * 2 <= power) {
|
||||
result = result * result;
|
||||
currentPower *= 2;
|
||||
}
|
||||
return result * exp10(power - currentPower);
|
||||
} else {
|
||||
return 1 / exp10(-power);
|
||||
}
|
||||
}
|
||||
|
||||
int gst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
|
||||
int sign = 1, x = 0;
|
||||
int64_t accum = 0;
|
||||
if (*string == '-') {
|
||||
sign = -1;
|
||||
++string;
|
||||
} else if (*string == '+') {
|
||||
++string;
|
||||
}
|
||||
if (string >= end) return 0;
|
||||
while (string < end) {
|
||||
x = *string;
|
||||
if (x < '0' || x > '9') return 0;
|
||||
x -= '0';
|
||||
accum = accum * 10 + x;
|
||||
++string;
|
||||
}
|
||||
*ret = accum * sign;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read a real from a string. Returns if successfuly
|
||||
* parsed a real from the enitre input string.
|
||||
* If returned 1, output is int ret.*/
|
||||
int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
|
||||
int sign = 1, x = 0;
|
||||
double accum = 0, exp = 1, place = 1;
|
||||
/* Check the sign */
|
||||
if (*string == '-') {
|
||||
sign = -1;
|
||||
++string;
|
||||
} else if (*string == '+') {
|
||||
++string;
|
||||
}
|
||||
if (string >= end) return 0;
|
||||
while (string < end) {
|
||||
if (*string == '.' && !forceInt) {
|
||||
place = 0.1;
|
||||
} else if (!forceInt && (*string == 'e' || *string == 'E')) {
|
||||
/* Read the exponent */
|
||||
++string;
|
||||
if (string >= end) return 0;
|
||||
if (!gst_read_real(string, end, &exp, 1))
|
||||
return 0;
|
||||
exp = exp10(exp);
|
||||
break;
|
||||
} else {
|
||||
x = *string;
|
||||
if (x < '0' || x > '9') return 0;
|
||||
x -= '0';
|
||||
if (place < 1) {
|
||||
accum += x * place;
|
||||
place *= 0.1;
|
||||
} else {
|
||||
accum *= 10;
|
||||
accum += x;
|
||||
}
|
||||
}
|
||||
++string;
|
||||
}
|
||||
*ret = accum * sign * exp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****/
|
||||
/* Module utils */
|
||||
/****/
|
||||
|
||||
static void gst_cmodule_register(Gst *vm, const char *name, const GstModuleItem *mod) {
|
||||
uint32_t startLength;
|
||||
GstBuffer *buffer = gst_buffer(vm, 10);
|
||||
|
@ -499,7 +499,7 @@ void gst_init(Gst *vm) {
|
||||
vm->nextCollection = 0;
|
||||
/* Setting memoryInterval to zero forces
|
||||
* a collection pretty much every cycle, which is
|
||||
* obviously horrible for performance, but helps ensure
|
||||
* horrible for performance, but helps ensure
|
||||
* there are no memory bugs during dev */
|
||||
vm->memoryInterval = 0;
|
||||
vm->black = 0;
|
||||
|
@ -654,6 +654,8 @@ int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap);
|
||||
#define GST_ENV_METADATA 1
|
||||
#define GST_ENV_VARS 2
|
||||
|
||||
int gst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt);
|
||||
int gst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret);
|
||||
GstReal gst_integer_to_real(GstInteger x);
|
||||
GstInteger gst_real_to_integer(GstReal x);
|
||||
GstInteger gst_startrange(GstInteger raw, uint32_t len);
|
||||
|
@ -8,4 +8,4 @@
|
||||
(var i 0)
|
||||
(while (< i 1000)
|
||||
(print i)
|
||||
(varset i (+ i 1)))
|
||||
(varset! i (+ i 1)))
|
||||
|
@ -1,27 +0,0 @@
|
||||
(namespace-set! "gst.repl")
|
||||
|
||||
"Read a line"
|
||||
(export! "readline" (fn []
|
||||
(: b (buffer))
|
||||
(read stdin 1 b)
|
||||
(while (not (= (get "\n" 0) (get b (- (length b) 1))))
|
||||
(read stdin 1 b)
|
||||
)
|
||||
(string b)
|
||||
))
|
||||
|
||||
"Create a parser"
|
||||
(export! "p" (parser))
|
||||
|
||||
"Run a simple repl."
|
||||
(while 1
|
||||
(write stdout ">> ")
|
||||
(: t (thread (fn [line]
|
||||
(: ret 1)
|
||||
(while line
|
||||
(: line (parse-charseq p line))
|
||||
(if (parse-hasvalue p)
|
||||
(: ret ((compile (parse-consume p))))))
|
||||
ret)))
|
||||
(: res (tran t (readline)))
|
||||
(if (= (status t) "dead") (print (debugp res)) (print "Error: " (debugp res))))
|
Loading…
Reference in New Issue
Block a user