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?
(var going true)
# The parser object
(def p (parser 1))
# Fiber stream of characters
(def chars (coro
(def buf @"")
(var len 1)
(while (< 0 len)
(buffer-clear buf)
(chunks buf)
(chunks buf p)
(:= len (length buf))
(for [i 0 len]
(yield (get buf i))))
@ -867,7 +870,6 @@ onvalue."
# Fiber stream of values
(def vals (coro
(def p (parser 1))
(while going
(switch (parser-status p)
:full (yield (parser-produce p))
@ -977,18 +979,18 @@ environment is needed, use run-context."
(:= k (next newenv k))))
(defmacro import [path & args]
(apply tuple import* '_env path args))
(apply tuple import* '_env path args))
(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."
(def newenv (make-env))
(defn chunks [buf]
(file-write stdout "> ")
(file-flush stdout)
(file-read stdin :line buf))
(defn chunks [buf p]
(file-write stdout (string (parser-state p) "> "))
(file-flush stdout)
(file-read stdin :line buf))
(defn onvalue [x]
(put newenv '_ @{:value x})
(pp x))
(put newenv '_ @{:value x})
(pp x))
(run-context newenv (if getchunk getchunk chunks)
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");
for (i = 1; i < args.n; i++) {
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));
}

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@
void dst_line_init();
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);
#endif

View File

@ -120,7 +120,10 @@ struct DstParseState {
#define PFLAG_CONTAINER 1
#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) {
DstParseState s;
@ -372,8 +375,8 @@ static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
return root(p, state, c);
}
#define PFLAG_INSTRING 8
#define PFLAG_END_CANDIDATE 16
#define PFLAG_INSTRING 64
#define PFLAG_END_CANDIDATE 128
static int longstring(DstParser *p, DstParseState *state, uint8_t c) {
if (state->flags & PFLAG_INSTRING) {
/* 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);
switch (c) {
case '{':
pushstate(p, dotable, PFLAG_CONTAINER);
pushstate(p, dotable, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
return 1;
case '"':
pushstate(p, stringchar, PFLAG_BUFFER);
pushstate(p, stringchar, PFLAG_BUFFER | PFLAG_STRING);
return 1;
case '\\':
pushstate(p, longstring, PFLAG_BUFFER);
pushstate(p, longstring, PFLAG_BUFFER | PFLAG_STRING);
return 1;
case '[':
pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
return 1;
case '(':
pushstate(p, doarray, PFLAG_CONTAINER);
pushstate(p, doarray, PFLAG_CONTAINER | PFLAG_PARENS);
return 1;
default:
break;
@ -479,13 +482,13 @@ static int root(DstParser *p, DstParseState *state, uint8_t c) {
p->error = "mismatched delimiter";
return 1;
case '(':
pushstate(p, dotuple, PFLAG_CONTAINER);
pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_PARENS);
return 1;
case '[':
pushstate(p, dotuple, PFLAG_CONTAINER | PFLAG_SQRBRACKETS);
return 1;
case '{':
pushstate(p, dostruct, PFLAG_CONTAINER);
pushstate(p, dostruct, PFLAG_CONTAINER | PFLAG_CURLYBRACKETS);
return 1;
}
}
@ -509,14 +512,18 @@ enum DstParserStatus dst_parser_status(DstParser *parser) {
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) {
enum DstParserStatus status = dst_parser_status(parser);
if (status == DST_PARSE_ERROR) {
const char *e = parser->error;
dst_v_empty(parser->argstack);
dst_v__cnt(parser->states) = 1;
parser->error = NULL;
dst_v_empty(parser->buf);
dst_parser_flush(parser);
return e;
}
return NULL;
@ -688,6 +695,36 @@ static int cfun_produce(DstArgs args) {
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 */
static int cfun_unwrap1(DstArgs args) {
if (args.n != 1) return dst_throw(args, "expected 1 argument");
@ -730,6 +767,8 @@ static const DstReg cfuns[] = {
{"parser-byte", cfun_byte},
{"parser-error", cfun_error},
{"parser-status", cfun_status},
{"parser-flush", cfun_flush},
{"parser-state", cfun_state},
{"ast-unwrap", cfun_unwrap},
{"ast-unwrap1", cfun_unwrap1},
{"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 and backslashes")
(print :hello)
(end-suite)