1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-30 17:13:15 +00:00

Add extra information in repl to show state of parsing.

This commit is contained in:
Calvin Rose 2018-05-06 23:25:59 -04:00
parent 7e63427208
commit 55f0e759d9
8 changed files with 88 additions and 31 deletions

View File

@ -853,13 +853,16 @@ onvalue."
# Are we done yet? # Are we done yet?
(var going true) (var going true)
# The parser object
(def p (parser 1))
# Fiber stream of characters # Fiber stream of characters
(def chars (coro (def chars (coro
(def buf @"") (def buf @"")
(var len 1) (var len 1)
(while (< 0 len) (while (< 0 len)
(buffer-clear buf) (buffer-clear buf)
(chunks buf) (chunks buf p)
(:= len (length buf)) (:= len (length buf))
(for [i 0 len] (for [i 0 len]
(yield (get buf i)))) (yield (get buf i))))
@ -867,7 +870,6 @@ onvalue."
# Fiber stream of values # Fiber stream of values
(def vals (coro (def vals (coro
(def p (parser 1))
(while going (while going
(switch (parser-status p) (switch (parser-status p)
:full (yield (parser-produce p)) :full (yield (parser-produce p))
@ -977,18 +979,18 @@ environment is needed, use run-context."
(:= k (next newenv k)))) (:= k (next newenv k))))
(defmacro import [path & args] (defmacro import [path & args]
(apply tuple import* '_env path args)) (apply tuple import* '_env path args))
(defn repl [getchunk] (defn repl [getchunk]
"Run a repl. The first parameter is an optional function to call to "Run a repl. The first parameter is an optional function to call to
get a chunk of source code. Should return nil for end of file." get a chunk of source code. Should return nil for end of file."
(def newenv (make-env)) (def newenv (make-env))
(defn chunks [buf] (defn chunks [buf p]
(file-write stdout "> ") (file-write stdout (string (parser-state p) "> "))
(file-flush stdout) (file-flush stdout)
(file-read stdin :line buf)) (file-read stdin :line buf))
(defn onvalue [x] (defn onvalue [x]
(put newenv '_ @{:value x}) (put newenv '_ @{:value x})
(pp x)) (pp x))
(run-context newenv (if getchunk getchunk chunks) (run-context newenv (if getchunk getchunk chunks)
onvalue default-error-handler)) onvalue default-error-handler))

View File

@ -221,7 +221,9 @@ static int dst_io_fwrite(DstArgs args) {
return dst_throw(args, "file is not writeable"); return dst_throw(args, "file is not writeable");
for (i = 1; i < args.n; i++) { for (i = 1; i < args.n; i++) {
if (!checkchars(args, i, &str, &len)) return 1; if (!checkchars(args, i, &str, &len)) return 1;
if (!fwrite(str, len, 1, iof->file)) return dst_throw(args, "error writing to file"); if (len) {
if (!fwrite(str, len, 1, iof->file)) return dst_throw(args, "error writing to file");
}
} }
return dst_return(args, dst_wrap_abstract(iof)); return dst_return(args, dst_wrap_abstract(iof));
} }

View File

@ -63,6 +63,7 @@ int dst_parser_consume(DstParser *parser, uint8_t c);
enum DstParserStatus dst_parser_status(DstParser *parser); enum DstParserStatus dst_parser_status(DstParser *parser);
Dst dst_parser_produce(DstParser *parser); Dst dst_parser_produce(DstParser *parser);
const char *dst_parser_error(DstParser *parser); const char *dst_parser_error(DstParser *parser);
void dst_parser_flush(DstParser *parser);
int dst_parse_cfun(DstArgs args); int dst_parse_cfun(DstArgs args);

View File

@ -2,6 +2,7 @@
(var *should-repl* :private false) (var *should-repl* :private false)
(var *no-file* :private true) (var *no-file* :private true)
(var *use-getline* :private true)
# Flag handlers # Flag handlers
(def handlers :private { (def handlers :private {
@ -10,11 +11,13 @@
(print "Options are:") (print "Options are:")
(print " -h Show this help") (print " -h Show this help")
(print " -v Print the version string") (print " -v Print the version string")
(print " -s Use raw stdin instead of getline like functionality")
(print " -e Execute a string of dst") (print " -e Execute a string of dst")
(print " -r Enter the repl after running all scripts") (print " -r Enter the repl after running all scripts")
(os-exit 0) (os-exit 0)
1) 1)
"v" (fn [] (print VERSION) (os-exit 0) 1) "v" (fn [] (print VERSION) (os-exit 0) 1)
"s" (fn [] (:= *use-getline* false) (:= *should-repl* true) 1)
"r" (fn [] (:= *should-repl* true) 1) "r" (fn [] (:= *should-repl* true) 1)
"e" (fn [i] "e" (fn [i]
(:= *no-file* false) (:= *no-file* false)
@ -38,8 +41,12 @@
(import arg) (import arg)
(++ i)))) (++ i))))
(defn xgetline [buf p]
(def prompt (string (parser-state p) "> "))
(getline prompt buf))
(when (or *should-repl* *no-file*) (when (or *should-repl* *no-file*)
(print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose")) (print (string "Dst " VERSION " Copyright (C) 2017-2018 Calvin Rose"))
(repl getline)) (repl (if *use-getline* xgetline)))
) )

View File

@ -24,9 +24,12 @@
/* Common */ /* Common */
int dst_line_getter(DstArgs args) { int dst_line_getter(DstArgs args) {
if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) dst_fixarity(args, 2);
return dst_throw(args, "expected buffer"); dst_check(args, 0, DST_STRING);
dst_line_get(dst_unwrap_buffer(args.v[0])); dst_check(args, 1, DST_BUFFER);
dst_line_get(
dst_unwrap_string(args.v[0]),
dst_unwrap_buffer(args.v[1]));
return dst_return(args, args.v[0]); return dst_return(args, args.v[0]);
} }
@ -54,8 +57,8 @@ void dst_line_deinit() {
; ;
} }
void dst_line_get(DstBuffer *buffer) { void dst_line_get(const uint8_t *p, DstBuffer *buffer) {
fputs("> ", stdout); fputs((const char *)p, stdout);
simpleline(buffer); simpleline(buffer);
} }
@ -431,7 +434,8 @@ static int checktermsupport() {
return 1; return 1;
} }
void dst_line_get(DstBuffer *buffer) { void dst_line_get(const uint8_t *p, DstBuffer *buffer) {
prompt = (const char *)p;
buffer->count = 0; buffer->count = 0;
historyi = 0; historyi = 0;
if (!isatty(STDIN_FILENO) || !checktermsupport()) { if (!isatty(STDIN_FILENO) || !checktermsupport()) {

View File

@ -28,7 +28,7 @@
void dst_line_init(); void dst_line_init();
void dst_line_deinit(); void dst_line_deinit();
void dst_line_get(DstBuffer *buffer); void dst_line_get(const uint8_t *p, DstBuffer *buffer);
int dst_line_getter(DstArgs args); int dst_line_getter(DstArgs args);
#endif #endif

View File

@ -120,7 +120,10 @@ struct DstParseState {
#define PFLAG_CONTAINER 1 #define PFLAG_CONTAINER 1
#define PFLAG_BUFFER 2 #define PFLAG_BUFFER 2
#define PFLAG_SQRBRACKETS 4 #define PFLAG_PARENS 4
#define PFLAG_SQRBRACKETS 8
#define PFLAG_CURLYBRACKETS 16
#define PFLAG_STRING 32
static void pushstate(DstParser *p, Consumer consumer, int flags) { static void pushstate(DstParser *p, Consumer consumer, int flags) {
DstParseState s; DstParseState s;
@ -372,8 +375,8 @@ static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
return root(p, state, c); return root(p, state, c);
} }
#define PFLAG_INSTRING 8 #define PFLAG_INSTRING 64
#define PFLAG_END_CANDIDATE 16 #define PFLAG_END_CANDIDATE 128
static int longstring(DstParser *p, DstParseState *state, uint8_t c) { static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
if (state->flags & PFLAG_INSTRING) { if (state->flags & PFLAG_INSTRING) {
/* We are inside the long string */ /* We are inside the long string */
@ -426,19 +429,19 @@ static int ampersand(DstParser *p, DstParseState *state, uint8_t c) {
dst_v_pop(p->states); dst_v_pop(p->states);
switch (c) { switch (c) {
case '{': case '{':
pushstate(p, dotable, PFLAG_CONTAINER); pushstate(p, dotable, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
return 1; return 1;
case '"': case '"':
pushstate(p, stringchar, PFLAG_BUFFER); pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
return 1; return 1;
case '\\': case '\\':
pushstate(p, longstring, PFLAG_BUFFER); pushstate(p, longstring, PFLAG_BUFFER | PFLAG_STRING);
return 1; return 1;
case '[': case '[':
pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_SQRBRACKETS); pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
return 1; return 1;
case '(': case '(':
pushstate(p, doarray, PFLAG_CONTAINER); pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_PARENS);
return 1; return 1;
default: default:
break; break;
@ -479,13 +482,13 @@ static int root(DstParser *p, DstParseState *state, uint8_t c) {
p->error = "mismatched delimiter"; p->error = "mismatched delimiter";
return 1; return 1;
case '(': case '(':
pushstate(p, dotuple, PFLAG_CONTAINER); pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_PARENS);
return 1; return 1;
case '[': case '[':
pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_SQRBRACKETS); pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
return 1; return 1;
case '{': case '{':
pushstate(p, dostruct, PFLAG_CONTAINER); pushstate(p, dostruct, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
return 1; return 1;
} }
} }
@ -509,14 +512,18 @@ enum DstParserStatus dst_parser_status(DstParser *parser) {
return DST_PARSE_ROOT; return DST_PARSE_ROOT;
} }
void dst_parser_flush(DstParser *parser) {
dst_v_empty(parser->argstack);
dst_v__cnt(parser->states) = 1;
dst_v_empty(parser->buf);
}
const char *dst_parser_error(DstParser *parser) { const char *dst_parser_error(DstParser *parser) {
enum DstParserStatus status = dst_parser_status(parser); enum DstParserStatus status = dst_parser_status(parser);
if (status == DST_PARSE_ERROR) { if (status == DST_PARSE_ERROR) {
const char *e = parser->error; const char *e = parser->error;
dst_v_empty(parser->argstack);
dst_v__cnt(parser->states) = 1;
parser->error = NULL; parser->error = NULL;
dst_v_empty(parser->buf); dst_parser_flush(parser);
return e; return e;
} }
return NULL; return NULL;
@ -688,6 +695,36 @@ static int cfun_produce(DstArgs args) {
return dst_return(args, val); return dst_return(args, val);
} }
static int cfun_flush(DstArgs args) {
DstParser *p = checkparser(args);
if (!p) return 1;
dst_parser_flush(p);
return dst_return(args, args.v[0]);
}
static int cfun_state(DstArgs args) {
int32_t i;
uint8_t *buf = NULL;
const uint8_t *str;
DstParser *p = checkparser(args);
if (!p) return 1;
for (i = 0; i < dst_v_count(p->states); i++) {
DstParseState *s = p->states + i;
if (s->flags & PFLAG_PARENS) {
dst_v_push(buf, '(');
} else if (s->flags & PFLAG_SQRBRACKETS) {
dst_v_push(buf, '[');
} else if (s->flags & PFLAG_CURLYBRACKETS) {
dst_v_push(buf, '{');
} else if (s->flags & PFLAG_STRING) {
dst_v_push(buf, '"');
}
}
str = dst_string(buf, dst_v_count(buf));
dst_v_free(buf);
return dst_return(args, dst_wrap_string(str));
}
/* AST */ /* AST */
static int cfun_unwrap1(DstArgs args) { static int cfun_unwrap1(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected 1 argument"); if (args.n != 1) return dst_throw(args, "expected 1 argument");
@ -730,6 +767,8 @@ static const DstReg cfuns[] = {
{"parser-byte", cfun_byte}, {"parser-byte", cfun_byte},
{"parser-error", cfun_error}, {"parser-error", cfun_error},
{"parser-status", cfun_status}, {"parser-status", cfun_status},
{"parser-flush", cfun_flush},
{"parser-state", cfun_state},
{"ast-unwrap", cfun_unwrap}, {"ast-unwrap", cfun_unwrap},
{"ast-unwrap1", cfun_unwrap1}, {"ast-unwrap1", cfun_unwrap1},
{"ast-wrap", cfun_wrap}, {"ast-wrap", cfun_wrap},

View File

@ -73,4 +73,6 @@
(assert (= "hello, \"world\"" \\hello, "world"\\), "long string with embedded quotes") (assert (= "hello, \"world\"" \\hello, "world"\\), "long string with embedded quotes")
(assert (= "hello, \\\\\\ \"world\"" \=\hello, \\\ "world"\=\), "long string with embedded quotes and backslashes") (assert (= "hello, \\\\\\ \"world\"" \=\hello, \\\ "world"\=\), "long string with embedded quotes and backslashes")
(print :hello)
(end-suite) (end-suite)